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

转载自:http://www.cnblogs.com/skywang12345/p/3496651.html点击打开链接

概要

前面两章分析了"公平锁的获取和释放机制",这一章开始对“非公平锁”的获取锁/释放锁的过程进行分析。内容包括:
参考代码
获取非公平锁(基于JDK1.7.0_40)
释放非公平锁(基于JDK1.7.0_40)
关于锁的数据结构请参考"Java多线程系列--“JUC锁”03之 公平锁(一) ",锁的使用示例请参考“Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock”。

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

 

参考代码

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

ReentranLock.java

 View Code

 

AQS(AbstractQueuedSynchronizer.java)

 View Code

 

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

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

 

1. lock()

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

final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(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) // overflowthrow 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等待队列排序等待。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/419243.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

空间点到直线的距离

作者&#xff1a;zdd出处&#xff1a;http://www.cnblogs.com/graphics/ 本文版权归作者和博客园共有&#xff0c;欢迎转载&#xff0c;但未经作者同意必须保留此段声明&#xff0c;且在文章页面明显位置给出原文连接&#xff0c;否则保留追究法律责任的权利.转载于:https://ww…

TCP面向连接中的“连接”和“可靠”与“不可靠”

转载自&#xff1a;http://blog.csdn.net/haizhongyun/article/details/7621199点击打开链接 连接是对状态的保持 实际上就是在客户端和服务器端都维护一个变量&#xff0c;这个变量维护现在数据传输的状态&#xff0c;例如传输了哪些数据&#xff0c;下一次需要传输哪些数据…

UIView常用的一些方法小记之setNeedsDisplay和setNeedsLayout

1,UIView的setNeedsDisplay和setNeedsLayout方法 首先两个方法都是异步执行的。而setNeedsDisplay会调用自动调用drawRect方法&#xff0c;这样可以拿到 UIGraphicsGetCurrentContext&#xff0c;就可以画画了。而setNeedsLayout会默认调用layoutSubViews&#xff0c; 就可以 …

深入理解Java中为什么内部类可以访问外部类的成员

转载自&#xff1a;http://blog.csdn.net/zhangjg_blog/article/details/20000769 内部类简介 虽然Java是一门相对比较简单的编程语言&#xff0c;但是对于初学者&#xff0c; 还是有很多东西感觉云里雾里&#xff0c; 理解的不是很清晰。内部类就是一个经常让初学者感到迷惑的…

JMS与Spring之二(用message listener container异步收发消息)

转自&#xff1a;http://blog.csdn.net/moonsheep_liu/article/details/6684948转载于:https://www.cnblogs.com/septemberlxc/p/5016275.html

ASP.NET MVC5+EF6+EasyUI 后台管理系统(51)-系统升级

系统很久没有更新内容了&#xff0c;期待已久的更新在今天发布了&#xff0c;最近花了2个月的时间每天一点点&#xff0c;从原有系统 MVC4EF5UNITY2.XQuartz 2.0easyui 1.3.4无缝接入 MVC5EF6Unity4.xQuartz 2.3 easyui 1.4.3. 并以easyui 1.4.3的gray皮肤为基础&#xff0c;升…

cocos2d-x-3.x 动作(5)序列动作

其实就是按照顺序来执行动作指令。 1 bool HelloWorld::init()2 {3 if (!Layer::init())4 {5 return false;6 }7 8 Size visibleSize Director::getInstance()->getVisibleSize();9 Sprite *label Sprite::create("what.png"); 10 …

前端学习(1696):前端系列javascript之class和继承

class Prople {constructor(name) {this.name name;}eat() {console.log(${this.name} eat something)} }//类 class Student extends Prople {constructor(name, number) {super(name);this.number number;}sayHi() {console.log(姓名 ${this.name} .学号 ${this.number})} …

vue的computed计算属性学习

模板内的表达式是非常便利的&#xff0c;但是它们实际上只用于简单的运算。在模板中放入太多的逻辑会让模板过重且难以维护。这时候需要使用到vue的计算属性computed。 文件目录结构如下&#xff1a;利用vue脚手架创建 这里实现将一个字符串进行翻转的功能&#xff1a; 其中H…

android错误详解教程二

原因&#xff1a;XML文件中<ImageView 写成<imageView 大小写写错转载于:https://www.cnblogs.com/-monster/p/5023969.html

js中小数取整数(向上、向下取整数,四舍五入取整数的实现)

1.ceil() 向上----------ceil英文意思&#xff1a;天花板-----------表示向上取整 2.floor() 向下-----------floor英文意思&#xff1a;地面-----------表示乡下取整 3.floor() 四舍五入----------floor英文意思&#xff1a;大约-----------表示四舍五入 如下实例&#xff1a…

subroutines of perl

#!/usr/bin/perl -wstudents qw/Doreen Oskar Elin Sangeet Malin/;&next_student;&next_student;sub next_student {$i;print "the next student is $students[$i]\n"; }the next student is Oskar the next student is Elin 转载于:https://www.cnblogs.c…

“睡服”面试官系列第十四篇之数组的扩展(建议收藏学习)

目录 1. 扩展运算符 1含义 1.2替代数组的 apply 方法 1.3扩展运算符的应用 1.3.1复制数组 1.3.2合并数组 1.3.3与解构赋值结合 1.3.4字符串 1.3.5实现了 Iterator 接口的对象 1.3.6Map 和 Set 结构&#xff0c;Generator 函数 2. Array.from() 3. Array.of() 4. 数…

数字证书及CA的扫盲介绍

转载自 http://kb.cnblogs.com/page/194742/★ 先说一个通俗的例子考虑到证书体系的相关知识比较枯燥、晦涩。俺先拿一个通俗的例子来说事儿。◇ 普通的介绍信想必大伙儿都听说过介绍信的例子吧&#xff1f;假设 A 公司的张三先生要到 B 公司去拜访&#xff0c;但是 B 公司的所…