转载请注明出处:http://www.cnblogs.com/skywang12345/p/3496651.html

参考代码

下面给出Java1.7.0_40版本中,ReentrantLock和AQS的源码,仅供参考!

ReentranLock.java

 

AQS(AbstractQueuedSynchronizer.java)

获取非公平锁(基于JDK1.7.0_40)

非公平锁和公平锁在获取锁的方法上,流程是一样的;它们的区别主要表现在“尝试获取锁的机制不同”。简单点说,“公平锁”在每次尝试获取锁时,都是采用公平策略(根据等待队列依次排序等待);而“非公平锁”在每次尝试获取锁时,都是采用的非公平策略(无视等待队列,直接尝试获取锁,如果锁是空闲的,即可获取状态,则获取锁)。
在前面的“Java多线程系列--“JUC锁”03之 公平锁(一)”中,已经详细介绍了获取公平锁的流程和机制;下面,通过代码分析以下获取非公平锁的流程。

1. lock()

lock()在ReentrantLock.java的NonfairSync类中实现,它的源码如下:

final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}

说明
lock()会先通过compareAndSet(0, 1)来判断“锁”是不是空闲状态。是的话,“当前线程”直接获取“锁”;否则的话,调用acquire(1)获取锁。
(01) compareAndSetState()是CAS函数,它的作用是比较并设置当前锁的状态。若锁的状态值为0,则设置锁的状态值为1。
(02) setExclusiveOwnerThread(Thread.currentThread())的作用是,设置“当前线程”为“锁”的持有者。

“公平锁”和“非公平锁”关于lock()的对比

公平锁   -- 公平锁的lock()函数,会直接调用acquire(1)。
非公平锁 -- 非公平锁会先判断当前锁的状态是不是空闲,是的话,就不排队,而是直接获取锁。

2. acquire()

acquire()在AQS中实现的,它的源码如下:

public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}

(01) “当前线程”首先通过tryAcquire()尝试获取锁。获取成功的话,直接返回;尝试失败的话,进入到等待队列依次排序,然后获取锁。
(02) “当前线程”尝试失败的情况下,会先通过addWaiter(Node.EXCLUSIVE)来将“当前线程”加入到"CLH队列(非阻塞的FIFO队列)"末尾。
(03) 然后,调用acquireQueued()获取锁。在acquireQueued()中,当前线程会等待它在“CLH队列”中前面的所有线程执行并释放锁之后,才能获取锁并返回。如果“当前线程”在休眠等待过程中被中断过,则调用selfInterrupt()来自己产生一个中断。

“公平锁”和“非公平锁”关于acquire()的对比

公平锁和非公平锁,只有tryAcquire()函数的实现不同;即它们尝试获取锁的机制不同。这就是我们所说的“它们获取锁策略的不同所在之处”!
在“Java多线程系列--“JUC锁”03之 公平锁(一)”中,已经详细介绍了acquire()涉及到的各个函数。这里仅对它们有差异的函数tryAcquire()进行说明。

非公平锁的tryAcquire()在ReentrantLock.java的NonfairSync类中实现,源码如下:

protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}

nonfairTryAcquire()在ReentrantLock.java的Sync类中实现,源码如下:

final boolean nonfairTryAcquire(int acquires) {
// 获取“当前线程”
final Thread current = Thread.currentThread();
// 获取“锁”的状态
int c = getState();
// c=0意味着“锁没有被任何线程锁拥有”
if (c == 0) {
// 若“锁没有被任何线程锁拥有”,则通过CAS函数设置“锁”的状态为acquires。
// 同时,设置“当前线程”为锁的持有者。
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
// 如果“锁”的持有者已经是“当前线程”,
// 则将更新锁的状态。
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}

说明
根据代码,我们可以分析出,tryAcquire()的作用就是尝试去获取锁。
(01) 如果“锁”没有被任何线程拥有,则通过CAS函数设置“锁”的状态为acquires,同时,设置“当前线程”为锁的持有者,然后返回true。
(02) 如果“锁”的持有者已经是当前线程,则将更新锁的状态即可。
(03) 如果不术语上面的两种情况,则认为尝试失败。

“公平锁”和“非公平锁”关于tryAcquire()的对比

公平锁和非公平锁,它们尝试获取锁的方式不同。
公平锁在尝试获取锁时,即使“锁”没有被任何线程锁持有,它也会判断自己是不是CLH等待队列的表头;是的话,才获取锁。
而非公平锁在尝试获取锁时,如果“锁”没有被任何线程持有,则不管它在CLH队列的何处,它都直接获取锁。

释放非公平锁(基于JDK1.7.0_40)

非公平锁和公平锁在释放锁的方法和策略上是一样的。
而在前面的“Java多线程系列--“JUC锁”04之 公平锁(二) ”中,已经对“释放公平锁”进行了介绍;这里就不再重复的进行说明。

总结
公平锁和非公平锁的区别,是在获取锁的机制上的区别。表现在,在尝试获取锁时 —— 公平锁,只有在当前线程是CLH等待队列的表头时,才获取锁;而非公平锁,只要当前锁处于空闲状态,则直接获取锁,而不管CLH等待队列中的顺序。
只有当非公平锁尝试获取锁失败的时候,它才会像公平锁一样,进入CLH等待队列排序等待。

Java锁--非公平锁的更多相关文章

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

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

  2. java面试-公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解

    一.公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解 公平锁:多个线程按照申请的顺序来获取锁. 非公平锁:多个线程获取锁的先后顺序与申请锁的顺序无关.[ReentrantLock 默认非公平.s ...

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

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

  4. Java最全锁剖析:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

    乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度,在Java和数据库中都有此概念对应的实际应用. 1.乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会 ...

  5. java ReentrantLock 公平锁 非公平锁 测试

    package reentrantlock; import java.util.ArrayList; import java.util.concurrent.locks.ReentrantLock; ...

  6. Java多线程系列--“JUC锁”05之 非公平锁

    概要 前面两章分析了"公平锁的获取和释放机制",这一章开始对“非公平锁”的获取锁/释放锁的过程进行分析.内容包括:参考代码获取非公平锁(基于JDK1.7.0_40)释放非公平锁(基 ...

  7. Java中的常见锁(公平和非公平锁、可重入锁和不可重入锁、自旋锁、独占锁和共享锁)

    公平和非公平锁 公平锁:是指多个线程按照申请的顺序来获取值.在并发环境中,每一个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个就占有锁,否者就会加入到等待队列中,以 ...

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

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

  9. 多线程编程-- part5.1 互斥锁之非公平锁-获取与释放

    非公平锁之获取锁 非公平锁和公平锁在获取锁的方法上,流程是一样的:它们的区别主要表现在“尝试获取锁的机制不同”.简单点说,“公平锁”在每次尝试获取锁时,都是采用公平策略(根据等待队列依次排序等待):而 ...

随机推荐

  1. javascript jssdk退出微信的方法

    javascript jssdk退出微信的方法 <pre> $('.tctip').on('click',function () { setTimeout("WeixinJSBr ...

  2. nginx 安全配置和限制访问

    nginx基本安全配置 配置ssl证书 listen 443 ssl; ssl_certificate /usr/local/nginx/conf/server.crt; ssl_certificat ...

  3. Spring之23:AbstractBeanFactory,Bean的加载

    <spring源码之:循环依赖> AbstractBeanFactory的作用:别名管理,单例创建与注册,工厂方法FactoryBean支持. 由图我们直接的看出,AbstractBean ...

  4. MogileFS表说明

    MogileFS大致的表说明如下 checksum:用来存放文件的校验和class:文件分类定义device:主机上的可用设备定义,包括设备可用空间,使用的权重等信息domain:域定义信息file: ...

  5. PAT-1003 Emergency (25 分) 最短路最大点权+求相同cost最短路的数量

    As an emergency rescue team leader of a city, you are given a special map of your country. The map s ...

  6. (二)CXF之用CXF官方工具生成客户端Client

    一.CXF工具的下载与使用 登录CXF官网:http://cxf.apache.org/download.html 下载,本系列使用的是3.1.5版本: 添加path环境变量 二.案例 2.1 发布w ...

  7. spring cloud Eureka 配置信息

    Eureka instance 一个服务,如:订单系统,会部署多台服务器,而每台服务器上提供的服务就是instance; 负载配置. Eureka service 指的是服务,提供一种特定功能的服务, ...

  8. Go part 4 数据容器(数组,slice,string,map,syncMap,list)

    数组 数组是值类型,因此改变副本的值,不会影响到本身 数组的定义:var 变量名 [元素数量] T 变量名(符合标识符要求即可) 元素数量(整型,可以是const中的值) T(可以是任意基本类型,包括 ...

  9. 关于ECharts甘特图的实现

    对于使用ECharts图表的步骤,每种图表都是一致的,相信大家也都了解 此处只分享甘特图的option,代码如下: option: { title: { text: '项目实施进度表', left: ...

  10. 关于vue.js的部分总结

    1.MVVM和MVC的区别: MVVM:是Model-View-ViewModel的简写,即模型-视图-视图模型 模型:后端传递的数据 试图:所看到的页面 视图模型:mvvm模式的核心,它是连接vie ...