硬件环境:

  CPU:AMD Phenom(tm) II X4 955 Processor

  Memory:8G

  SSD(128G):/

  HDD(1T):/home/

软件环境:

  OS:Ubuntu14.04.3 LTS

  Java:JDK1.7

  关于ReentrantLock中非公平锁和公平锁详细区别以及实现方式在这里不再叙述,有关ReentrantLock的源码解析参照。

  首先我们用实例验证,非公平锁以及公平锁是否是其介绍的那样,非公平锁在获取锁的时候会首先进行抢锁,在获取锁失败后才会将当前线程加入同步队列队尾中,而公平锁则是符合请求的绝对顺序,也就是会按照先来后到FIFO。

 package com.lock;

 import org.junit.Test;

 import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by yulinfeng on 5/24/17.
*/
public class FairAndUnfairTest {
private static Lock fairLock = new ReentrantLockMine(true);
private static Lock unfairLock = new ReentrantLockMine(false); @Test
public void unfair() throws InterruptedException {
testLock("非公平锁", unfairLock);
} @Test
public void fair() throws InterruptedException {
testLock("公平锁", fairLock);
} private void testLock(String type, Lock lock) throws InterruptedException {
System.out.println(type);
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Job(lock)){
public String toString() {
return getName();
}
};
thread.setName("" + i);
thread.start();
}
Thread.sleep(11000);
} private static class Job implements Runnable{
private Lock lock;
public Job(Lock lock) {
this.lock = lock;
} public void run() {
for (int i = 0; i < 2; i++) {
lock.lock();
try {
Thread.sleep(1000);
System.out.println("获取锁的当前线程[" + Thread.currentThread().getName() + "], 同步队列中的线程" + ((ReentrantLockMine)lock).getQueuedThreads() + "");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
} private static class ReentrantLockMine extends ReentrantLock { //重新实现ReentrantLock类是为了重写getQueuedThreads方法,便于我们试验的观察
public ReentrantLockMine(boolean fair) {
super(fair);
} @Override
protected Collection<Thread> getQueuedThreads() { //获取同步队列中的线程
List<Thread> arrayList = new ArrayList<Thread>(super.getQueuedThreads());
Collections.reverse(arrayList);
return arrayList;
}
}
}

  上面这段代码:创建5个线程,每个线程中有两次获取锁与释放锁的行为。运行代码观察结果:

  

  显然,试验结果与我们的预期相符。在以非公平锁的方式获取锁,当一个线程在获取锁又释放锁,但又立即获取锁的时候,这个时候这个线程有很大的概率会成功(只是很大概率,试验结果也有可能不连续两次获取锁)。而公平锁则不一样,哪怕是同一个线程连续两次获取锁和释放锁,在第一次获取锁释放锁过后接着准备第二次获取锁时,这个时候当前线程会被加入到同步队列的队尾。

  那么有了上面的结果除了说明非公平锁和公平锁之间的区别还能说明什么问题呢?其实,这就是本篇的主题——性能测试。非公平锁的一个线程连续两次获取锁和释放锁的工程中,是没有做上下文切换的,也就是一共只做了5次上下文切换。而公平锁实际上做了10次上下文切换。而这个上下文切换的开销实际是很大的,我们通过测试在10个线程,每个线程获取100000次锁的情况下两者的执行速度,以及使用vmstat命令来统计系统上下文切换的次数(cs栏表示系统每秒切换的上下文次数)。

 package com.lock;

 import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* 改进后的代码,利用CyclicBarrier当所有线程执行完毕时,统计执行时间。
* Created by yulinfeng on 5/24/17.
*/
public class newFairAndUnfairLockTest {
private static Lock lock = new ReentrantLockMine(false); //非公平锁
//private static Lock lock = new ReentrantLockMine(true); //公平锁 public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
String lockType = "非公平锁";  //String lockType = "公平锁"
long start = System.currentTimeMillis();
CyclicBarrier cyclicBarrier = new CyclicBarrier(10, new Time(lockType, start)); //10个线程执行完毕时,执行Time线程统计执行时间 for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new Job(lock, cyclicBarrier)){
public String toString() {
return getName();
}
};
thread.setName("" + i);
thread.start();
} } private static class Job implements Runnable{
private Lock lock;
private CyclicBarrier cyclicBarrier;
public Job(Lock lock, CyclicBarrier cyclicBarrier) {
this.lock = lock;
this.cyclicBarrier = cyclicBarrier;
} public void run() {
for (int i = 0; i < 100000; i++) {
lock.lock();
try {
System.out.println(i+"获取锁的当前线程[" + Thread.currentThread().getName() + "], 同步队列中的线程" + ((ReentrantLockMine)lock).getQueuedThreads() + "");
} finally {
lock.unlock();
}
}
try {
cyclicBarrier.await(); //计数器+1,直到10个线程都到达
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
} private static class ReentrantLockMine extends ReentrantLock { //重新实现ReentrantLock类是为了重写getQueuedThreads方法,便于我们试验的观察
public ReentrantLockMine(boolean fair) {
super(fair);
} @Override
protected Collection<Thread> getQueuedThreads() { //获取同步队列中的线程
List<Thread> arrayList = new ArrayList<Thread>(super.getQueuedThreads());
Collections.reverse(arrayList);
return arrayList;
}
} private static class Time implements Runnable { //用于统计时间
private long start ;
private String lockType; public Time(String lockType, long start) {
this.start = start;
this.lockType = lockType;
} public void run() {
System.out.println(lockType + "耗时:" + String.valueOf(System.currentTimeMillis() - start));
}
}
}

  首先执行非公平锁,并使用"vmstat 1(每秒实时查看系统资源占用情况)",结果如下:

  

  

  再执行公平锁,并使用"vmstat 1(每秒实时查看系统资源占用情况)",结果如下:  

  

  

  通过上面的试验结果可以得出结论,非公平锁的性能因其系统上下文的切换较少,其性能一般要优于公平锁。

  

【试验局】ReentrantLock中非公平锁与公平锁的性能测试的更多相关文章

  1. java多线程20 : ReentrantLock中的方法 ,公平锁和非公平锁

    公平锁与非公平锁 ReentrantLock有一个很大的特点,就是可以指定锁是公平锁还是非公平锁,公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的,而非公平锁就是一种获取锁的抢占机制,是随机获得 ...

  2. 第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()

    最常用的方式: int a = 12; //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁 final Reentrant ...

  3. ReentrantLock可重入锁、公平锁非公平锁区别与实现原理

    ReentrantLock是lock接口的一个实现类,里面实现了可重入锁和公平锁非公平锁 ReentrantLock公平锁和不公平锁实现原理 公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取 ...

  4. java多线程:并发包中ReentrantLock锁的公平锁原理

    一:锁的原理结构 (1)锁对象内部维护了一个同步管理器的对象AbstractQueuedSynchronizer,AbstractOwnableSynchronizer (2)该对象其实是一个抽象类, ...

  5. 可重入锁 公平锁 读写锁、CLH队列、CLH队列锁、自旋锁、排队自旋锁、MCS锁、CLH锁

    1.可重入锁 如果锁具备可重入性,则称作为可重入锁. ========================================== (转)可重入和不可重入 2011-10-04 21:38 这 ...

  6. JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁,

    如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常遇到多个线程访问同一个 ...

  7. 最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

    在Java并发场景中,会涉及到各种各样的锁如公平锁,乐观锁,悲观锁等等,这篇文章介绍各种锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 乐观锁/悲观锁 分段锁 自旋锁 01.乐观锁 vs 悲观 ...

  8. lock 默认公平锁还是非公平锁?公平锁是如何定义?如何实现

    ReentrantLock的实现是基于其内部类FairSync(公平锁)和NonFairSync(非公平锁)实现的. 其可重入性是基于Thread.currentThread()实现的: 如果当前线程 ...

  9. Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等

    Java 中15种锁的介绍 Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等,在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类 ...

随机推荐

  1. asp.net core源码飘香:从Hosting开始

    知识点: 1.Kestrel服务器启动并处理Http请求的过程. 2.Startup的作用. 源码飘香: 总结: asp.net core将web开发拆分为多个独立的组件,大多以http中间件的形式添 ...

  2. java 基础知识七 装箱和拆箱

    java  基础知识七  装箱和拆箱 数据类型可分为两大种,基本数据类型(值类型)和类类型(引用数据类型) 装箱:把基本类型用他们相对应的引用类型包装起来,使他们可以具有对象的特质    基本数据类型 ...

  3. IDEA 根据数据库表 生成 Model实体

    首先在 Idea中 配置数据源,测试ok(过程略) idea窗口中左下角是否 有显示Persistence 窗口  如果没有显示就要如下方法 添加显示: File - > Project Str ...

  4. JavaScript--------------------jQuery中.bind() .live() .delegate() .on()的区别 和 三种方式写光棒事件 动画

    bind(type,[data],fn) 为每个匹配元素的特定事件绑定事件处理函数. $("a").bind("click",function(){alert( ...

  5. JS数组根据属性来实现排序

    var data = [{ name: "zhao", age: }, { name: "qian", age: }, { name: "sun&qu ...

  6. js距离现在时间计算

    <script language="javascript"> var biryear = 2015; var birmonth = 12; var birday = 1 ...

  7. 学习MVC之租房网站(四)-实现Service层并进行单元测试

    在上一篇<学习MVC之租房网站(三)-编写Eneity类并创建数据库>中,记录了编写Eneity类并采用CodeFirst的方式创建数据库的过程,接下来就到了Service层的实现了,并且 ...

  8. ESLint系列:ESLint入门安装及简单配置

    1.eslint需要依赖node.js环境,在配置之前需要安装好node.js; 2.npm install eslint --save-dev 或 npm install eslint --save ...

  9. 【2017-04-21】Ado.Nte属性扩展

    通过对数据库表的封装,对该表的属性进行扩展. 1.例如:表中的性别是bool类,要实现显示给用户看的为“男.女” 2.通过表中的生日datetime类,来实现显示给用户看的年月日,自动计算年龄. 3. ...

  10. es6面试问题——Promise

    话说刚换工作一个月有余,在上家公司干的实在是不开心,然后就出来抱着试试的心态出来面了几家公司,大多数公司问的前端问题也就那么多,其中有个面试问题让我记忆犹新,只因为没有答上来,哈哈! 当时面试官问我怎 ...