硬件环境:

  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. 深入浅出数据结构C语言版(7)——特殊的表:队列与栈

    从深入浅出数据结构(4)到(6),我们分别讨论了什么是表.什么是链表.为什么用链表以及如何用数组模拟链表(游标数组),而现在,我们要进入到对线性表(特意加了"线性"二字是因为存在多 ...

  2. 前端必备PS技巧

    hai,how is it going?I'm MuQing.I come back.哈哈,最近在英语的路上奋战,小秀一下.又好久没写博客了,实习的生活渐行渐远了,回到学校也终于能够坐下来对很多东西进 ...

  3. 轻量级操作系统FreeRTOS的内存管理机制(一)

    本文由嵌入式企鹅圈原创团队成员朱衡德(Hunter_Zhu)供稿. 近几年来,FreeRTOS在嵌入式操作系统排行榜中一直位居前列,作为开源的嵌入式操作系统之一,它支持许多不同架构的处理器以及多种编译 ...

  4. SQL Server 跨库复制表方法小笔记

    insert into tableA (column1,column2.....) SELECT * FROM OPENDATASOURCE('SQLOLEDB', 'Data Source=127. ...

  5. for xml path 如何将字段转换为xml的属性

    for xml path 如何将字段作为xml的属性: 可在查询时 别名用 as '@..' 如'@value' 如下实例: SELECT A.GiftSetGUID AS '@value',A.Gi ...

  6. Apriori算法(C#)

    AprioriMethod.cs using System; using System.Collections.Generic; using System.Linq; using System.Web ...

  7. Reids详解-抄本

    1.redis是什么 Redis 是一个基于内存的高性能key-value数据库.是一个开源的.使用C语言编写的.支持网络交互的.可基于内存也可持久化的Key-Value数据库. 2.redis的特点 ...

  8. Nginx反向代理以及负载均衡配置

    项目地址:http://git.oschina.net/miki-long/nginx 前提:最近在研究nginx的用法,在windows上小试了一下,由于windows下不支持nginx缓存配置,所 ...

  9. yeoman 使用问题总结

    1.今天尝试使用yeoman,执行grunt server 时报错: cannot find where you keep your bower packges 需要将bower npm instal ...

  10. kafka环境

    二.环境搭建 参考:http://kafka.apache.org/documentation.html#quickstartStep 1: 下载Kafkawget http://mirrors.no ...