硬件环境:

  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. coolpad 5879logcat不能输入日志解决办法

    有几天没完手机了,玩一下,发现不能打印日志了,记得最开始的时候 会弹出一个选项选择是否输出日志,在网上找了好的方法. 1.重启adb,点击DBMS 进行刷新. 2重启eclipse. 3.重装驱动. ...

  2. Android系统结构

    从上图中可以看出,Android系统架构为四层结构,从上层到下层分别是应用程序层.应用程序框架层.系统运行库层以及Linux内核层,分别介绍如下: (1)Appliacation Android平台不 ...

  3. How To Use ggplot2

    0. Preparation and Introduction ggplot2是R中新颖的数据可视化包,这得益于Leland Wilkinson在他的著作<The Grammar of Grap ...

  4. java小题:福尔摩斯的约会

    原题地址:https://www.nowcoder.com/pat/6/problem/4040 防止广告嫌疑,原题为: 题目描述 大侦探福尔摩斯接到一张奇怪的字条:"我们约会吧! 3485 ...

  5. C# SMTP发送邮件

    public void SendMail() { MailMessage mail = new MailMessage(); mail.From = new MailAddress("fro ...

  6. Unity3D 预备知识:C#与Lua相互调用

    在使用Unity开发游戏以支持热更新的方案中,使用ULua是比较成熟的一种方案.那么,在使用ULua之前,我们必须先搞清楚,C#与Lua是怎样交互的了? 简单地说,c#调用lua, 是c# 通过Pin ...

  7. DirectFB 之 字体显示(2)

    框架 示例代码 /********************************************** * Author: younger.liucn@hotmail.com * File n ...

  8. iOS APP打包分发给远程的手机测试

    APP要打包给远程的朋友或客户测试,但又不是企业账号的情况下,我们只能根据手机的udid进行描述证书的配置,再打包分发给提供了udid的手机进行安装 一.如何得到udid? 手机连接到mac电脑,打开 ...

  9. 【lucene系列学习二】Lucene实现高亮显示关键词

    首先,导入下图所示库 然后,import org.apache.lucene.search.highlight.*; 下面,我们新建一个实现高亮显示功能的函数 public static String ...

  10. (详细)php实现留言板---会话控制-----------2017-05-08

    要实现留言功能,发送者和接受者必不可少,其次就是留言时间留言内容. 要实现的功能: 1.登录者只能查看自己和所有人的信息,并能够给好友留言 2.留言板页面,好友采取下拉列表,当留言信息为空时,显示提示 ...