硬件环境:

  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。

  1. package com.lock;
  2.  
  3. import org.junit.Test;
  4.  
  5. import java.util.ArrayList;
  6. import java.util.Collection;
  7. import java.util.Collections;
  8. import java.util.List;
  9. import java.util.concurrent.locks.Lock;
  10. import java.util.concurrent.locks.ReentrantLock;
  11.  
  12. /**
  13. * Created by yulinfeng on 5/24/17.
  14. */
  15. public class FairAndUnfairTest {
  16. private static Lock fairLock = new ReentrantLockMine(true);
  17. private static Lock unfairLock = new ReentrantLockMine(false);
  18.  
  19. @Test
  20. public void unfair() throws InterruptedException {
  21. testLock("非公平锁", unfairLock);
  22. }
  23.  
  24. @Test
  25. public void fair() throws InterruptedException {
  26. testLock("公平锁", fairLock);
  27. }
  28.  
  29. private void testLock(String type, Lock lock) throws InterruptedException {
  30. System.out.println(type);
  31. for (int i = 0; i < 5; i++) {
  32. Thread thread = new Thread(new Job(lock)){
  33. public String toString() {
  34. return getName();
  35. }
  36. };
  37. thread.setName("" + i);
  38. thread.start();
  39. }
  40. Thread.sleep(11000);
  41. }
  42.  
  43. private static class Job implements Runnable{
  44. private Lock lock;
  45. public Job(Lock lock) {
  46. this.lock = lock;
  47. }
  48.  
  49. public void run() {
  50. for (int i = 0; i < 2; i++) {
  51. lock.lock();
  52. try {
  53. Thread.sleep(1000);
  54. System.out.println("获取锁的当前线程[" + Thread.currentThread().getName() + "], 同步队列中的线程" + ((ReentrantLockMine)lock).getQueuedThreads() + "");
  55. } catch (InterruptedException e) {
  56. e.printStackTrace();
  57. } finally {
  58. lock.unlock();
  59. }
  60. }
  61. }
  62. }
  63.  
  64. private static class ReentrantLockMine extends ReentrantLock { //重新实现ReentrantLock类是为了重写getQueuedThreads方法,便于我们试验的观察
  65. public ReentrantLockMine(boolean fair) {
  66. super(fair);
  67. }
  68.  
  69. @Override
  70. protected Collection<Thread> getQueuedThreads() { //获取同步队列中的线程
  71. List<Thread> arrayList = new ArrayList<Thread>(super.getQueuedThreads());
  72. Collections.reverse(arrayList);
  73. return arrayList;
  74. }
  75. }
  76. }

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

  

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

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

  1. package com.lock;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.Collection;
  5. import java.util.Collections;
  6. import java.util.List;
  7. import java.util.concurrent.BrokenBarrierException;
  8. import java.util.concurrent.CyclicBarrier;
  9. import java.util.concurrent.locks.Lock;
  10. import java.util.concurrent.locks.ReentrantLock;
  11.  
  12. /**
  13. * 改进后的代码,利用CyclicBarrier当所有线程执行完毕时,统计执行时间。
  14. * Created by yulinfeng on 5/24/17.
  15. */
  16. public class newFairAndUnfairLockTest {
  17. private static Lock lock = new ReentrantLockMine(false); //非公平锁
  18. //private static Lock lock = new ReentrantLockMine(true); //公平锁
  19.  
  20. public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
  21. String lockType = "非公平锁";  //String lockType = "公平锁"
  22. long start = System.currentTimeMillis();
  23. CyclicBarrier cyclicBarrier = new CyclicBarrier(10, new Time(lockType, start)); //10个线程执行完毕时,执行Time线程统计执行时间
  24.  
  25. for (int i = 0; i < 10; i++) {
  26. Thread thread = new Thread(new Job(lock, cyclicBarrier)){
  27. public String toString() {
  28. return getName();
  29. }
  30. };
  31. thread.setName("" + i);
  32. thread.start();
  33. }
  34.  
  35. }
  36.  
  37. private static class Job implements Runnable{
  38. private Lock lock;
  39. private CyclicBarrier cyclicBarrier;
  40. public Job(Lock lock, CyclicBarrier cyclicBarrier) {
  41. this.lock = lock;
  42. this.cyclicBarrier = cyclicBarrier;
  43. }
  44.  
  45. public void run() {
  46. for (int i = 0; i < 100000; i++) {
  47. lock.lock();
  48. try {
  49. System.out.println(i+"获取锁的当前线程[" + Thread.currentThread().getName() + "], 同步队列中的线程" + ((ReentrantLockMine)lock).getQueuedThreads() + "");
  50. } finally {
  51. lock.unlock();
  52. }
  53. }
  54. try {
  55. cyclicBarrier.await(); //计数器+1,直到10个线程都到达
  56. } catch (InterruptedException e) {
  57. e.printStackTrace();
  58. } catch (BrokenBarrierException e) {
  59. e.printStackTrace();
  60. }
  61. }
  62. }
  63.  
  64. private static class ReentrantLockMine extends ReentrantLock { //重新实现ReentrantLock类是为了重写getQueuedThreads方法,便于我们试验的观察
  65. public ReentrantLockMine(boolean fair) {
  66. super(fair);
  67. }
  68.  
  69. @Override
  70. protected Collection<Thread> getQueuedThreads() { //获取同步队列中的线程
  71. List<Thread> arrayList = new ArrayList<Thread>(super.getQueuedThreads());
  72. Collections.reverse(arrayList);
  73. return arrayList;
  74. }
  75. }
  76.  
  77. private static class Time implements Runnable { //用于统计时间
  78. private long start ;
  79. private String lockType;
  80.  
  81. public Time(String lockType, long start) {
  82. this.start = start;
  83. this.lockType = lockType;
  84. }
  85.  
  86. public void run() {
  87. System.out.println(lockType + "耗时:" + String.valueOf(System.currentTimeMillis() - start));
  88. }
  89. }
  90. }

  首先执行非公平锁,并使用"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. Struts2基础学习(五)—拦截器

    一.概述 1.初识拦截器      Interceptor 拦截器类似前面学过的过滤器,是可以在action执行前后执行的代码,是我们做Web开发经常用到的技术.比如:权限控制.日志等.我们也可以将多 ...

  2. 编译MangosZero

    最近研究了一下魔兽世界模拟器MangosZero,花了两天时间终于编译成功!现在把编译的过程做个完整的记录,以便让想要学习编译的同学们少走弯路! 服务器端运行界面: 客户端运行界面: 一:下载源程序 ...

  3. MySql字符串函数使用技巧

    1.从左开始截取字符串 left(str, length) 说明:left(被截取字段,截取长度) 例:select left(content,200) as abstract from my_con ...

  4. 利用原生JS判断组合键

    <script type="text/javascript"> var isAlt = 0; var isEnt = 0; document.onkeydown = f ...

  5. 【Linux配置】vim配置文件内容

    vim的配置 文件:~/.vimrc 在自己的家目录中的.vimrc文件进行编辑配置 设置如下: set nu "序号 set tabstop= "tab键的大小 set show ...

  6. 利用伪元素和css3实现鼠标移入下划线向两边展开效果

    一.思路: 将伪元素:before和:after定位到元素底部中间,设置宽度从0变成100%达到目的. 二.实现: 1.首先定义一个块状元素(行内元素没有宽高)并修改样式为一个背景色为浅灰色的矩形,设 ...

  7. STM32F4XX与STM32F0XX编程差别

    //普通管脚初始化 /*****************************************************************************STM32F0***** ...

  8. iOS·官方文档译文框架源码注解

    导语

  9. windows下安装Redis并部署成服务

    windows下安装Redis并部署成服务 Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库.缓存和消息中间件. 一:下载 下载地址: windows版本: http ...

  10. cmd第一次推送github

    echo off for %%i in ("%cd%") do set "name=%%~ni" git init git remote add origin ...