多线程编程-- part5.1 互斥锁之非公平锁-获取与释放
非公平锁之获取锁
非公平锁和公平锁在获取锁的方法上,流程是一样的;它们的区别主要表现在“尝试获取锁的机制不同”。简单点说,“公平锁”在每次尝试获取锁时,都是采用公平策略(根据等待队列依次排序等待);而“非公平锁”在每次尝试获取锁时,都是采用的非公平策略(无视等待队列,直接尝试获取锁,如果锁是空闲的,即可获取状态,则获取锁)。
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()函数的实现不同;即它们尝试获取锁的机制不同。这就是我们所说的“它们获取锁策略的不同所在之处”!
非公平锁的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队列的何处,它都直接获取锁。
释放非公平锁
非公平锁和公平锁在释放锁的方法和策略上是一样的。
总结
公平锁和非公平锁的区别,是在获取锁的机制上的区别。表现在,在尝试获取锁时 —— 公平锁,只有在当前线程是CLH等待队列的表头时,才获取锁;而非公平锁,只要当前锁处于空闲状态,则直接获取锁,而不管CLH等待队列中的顺序。
只有当非公平锁尝试获取锁失败的时候,它才会像公平锁一样,进入CLH等待队列排序等待。
多线程编程-- part5.1 互斥锁之非公平锁-获取与释放的更多相关文章
- 多线程编程-- part5.1 互斥锁之公平锁-获取锁
基本概念 1.AQS:AbstractQueuedSynchronizer类 AQS是java中管理“锁”的抽象类,锁的许多公共方法都是在这个类中实现.AQS是独占锁(例如,ReentrantLock ...
- 多线程编程-- part5.1 互斥锁ReentrantLock
ReentrantLock简介 Reentrantlock是一个可重入的互斥锁,又被称为独占锁. Reentrantlock:分为公平锁和非公平锁,它们的区别体现在获取锁的机制上是否公平.“锁”是为了 ...
- Java中的锁-悲观锁、乐观锁,公平锁、非公平锁,互斥锁、读写锁
总览图 如果文中内容有错误,欢迎指出,谢谢. 悲观锁.乐观锁 悲观锁.乐观锁使用场景是针对数据库操作来说的,是一种锁机制. 悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数 ...
- Java并发编程锁之独占公平锁与非公平锁比较
Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家去排队本着先来 ...
- “全栈2019”Java多线程第二十八章:公平锁与非公平锁详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java多线程--公平锁与非公平锁
上一篇文章介绍了AQS的基本原理,它其实就是一个并发包的基础组件,用来实现各种锁,各种同步组件的.它包含了state变量.加锁线程.等待队列等并发中的核心组件,现在我们来看一下多线程获取锁的顺序问题. ...
- java多线程20 : ReentrantLock中的方法 ,公平锁和非公平锁
公平锁与非公平锁 ReentrantLock有一个很大的特点,就是可以指定锁是公平锁还是非公平锁,公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的,而非公平锁就是一种获取锁的抢占机制,是随机获得 ...
- java并发库 Lock 公平锁和非公平锁
jdk1.5并发包中ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或非公平锁,关于两者区别,java并发编程实践里面有解释 公平锁: Threads acquir ...
- Java中的公平锁和非公平锁实现详解
前言 Java语言中有许多原生线程安全的数据结构,比如ArrayBlockingQueue.CopyOnWriteArrayList.LinkedBlockingQueue,它们线程安全的实现方式并非 ...
随机推荐
- 解决autowaired注入时机问题
package com.haiyisoft.loveLifeWeb.config; import javax.annotation.PostConstruct; import org.springfr ...
- 安装RabbitMq,写程序发送接收消息
1.安装Erlang和RabbitMq 在安装RabbitMq之前需要安装的Erlang(esl-erlang_22.0_windows_amd64.exe): https://pan.baidu.c ...
- 2.ibatis执行流程解析
以下仅为个人理解,如有问题,欢迎指正
- TensorFlow 学习(6)———TensorFlow运作方式
本部分主要涉及到TensorFlow的运作方式和主要操作 所需的代码在https://github.com/tensorflow/tensorflow/tree/master/tensorflow/e ...
- 数据解析框架之Gson
GSON是由Google提供的,用于JAVA对象与JSON字符串之间互相转换的一个解决方案.用处很多,比如在前后台通讯中,前台先将java对象转化成JSON,然后将JSON传输给后台交由后台处理——相 ...
- Android studio2 中的 SDK Manager的使用-------Android SDK 的安装与更新(Install missing platform(s) and sync project 编译错误解决)
最近在编写Android程序,其中有一个问题就是对旧应用的导入,此时往往你的Android SDK中并没有老版本的Android SDK, 此时往往会提示你出现错误 Install missing p ...
- IIS 报错试图加载格式不正确的程序集解决办法
原因: 64位系统和32系统不匹配导致. 解决办法: 方法一.注册32位IIS(必须卸载64位IIS) 使用命令 X:WindowsMicrosoft.NETFramework64v4.0.30319 ...
- Java split(".") 和 split("\\.")
Java split(".") 和 split("\\.") 问题描述 使用 . 分解 IP 的各个段,并打印,如:192.168.10.123,分解为 192 ...
- C# 线程安全集合类
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/kang_xuan/article/de ...
- 从gopath到go mod的一次尝试
windows下的尝试: gomod初尝试下载官方包1.11(及其以上版本将会自动支持gomod) 默认GO111MODULE=auto(auto是指如果在gopath下不启用mod)go mod h ...