ReentrantLock的实现是基于其内部类FairSync(公平锁)和NonFairSync(非公平锁)实现的。 其可重入性是基于Thread.currentThread()实现的: 如果当前线程已经获得了执行序列中的锁, 那执行序列之后的所有方法都可以获得这个锁。

公平锁:

公平和非公平锁的队列都基于锁内部维护的一个双向链表,表结点Node的值就是每一个请求当前锁的线程。公平锁则在于每次都是依次从队首取值。
锁的实现方式是基于如下几点:

  • 表结点Node和状态state的volatile关键字。
  • sum.misc.Unsafe.compareAndSet的原子操作(见附录)。

非公平锁:

在等待锁的过程中, 如果有任意新的线程妄图获取锁,都是有很大的几率直接获取到锁的。

  • ReentrantLock锁都不会使得线程中断,除非开发者自己设置了中断位。
  • ReentrantLock获取锁里面有看似自旋的代码,但是它不是自旋锁。
  • ReentrantLock公平与非公平锁都是属于排它锁。

公平锁和非公平锁在说的获取上都使用到了 volatile 关键字修饰的state字段, 这是保证多线程环境下锁的获取与否的核心。
但是当并发情况下多个线程都读取到 state == 0时,则必须用到CAS技术,一门CPU的原子锁技术,可通过CPU对共享变量加锁的形式,实现数据变更的原子操作。
volatile 和 CAS的结合是并发抢占的关键。

公平锁的实现机理在于每次有线程来抢占锁的时候,都会检查一遍有没有等待队列,如果有, 当前线程会执行如下步骤:

         /**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}

其中hasQueuedPredecessors是用于检查是否有等待队列的。

非公平锁在实现的时候多次强调随机抢占:

         /**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}

当当前拥有锁的线程释放锁之后, 且非公平锁无线程抢占,就开始线程唤醒的流程。 
通过tryRelease释放锁成功,调用LockSupport.unpark(s.thread); 终止线程阻塞

     private void unparkSuccessor(Node node) {
// 强行回写将被唤醒线程的状态
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
// s为h的下一个Node, 一般情况下都是非Null的
if (s == null || s.waitStatus > 0) {
s = null;
// 否则按照FIFO原则寻找最先入队列的并且没有被Cancel的Node
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// 再唤醒它
if (s != null)
LockSupport.unpark(s.thread);
}

非公平锁性能高于公平锁性能的原因:

在恢复一个被挂起的线程与该线程真正运行之间存在着严重的延迟。

假设线程A持有一个锁,并且线程B请求这个锁。由于锁被A持有,因此B将被挂起。当A释放锁时,B将被唤醒,因此B会再次尝试获取这个锁。与此同时,如果线程C也请求这个锁,那么C很可能会在B被完全唤醒之前获得、使用以及释放这个锁。这样就是一种双赢的局面:B获得锁的时刻并没有推迟,C更早的获得了锁,并且吞吐量也提高了。

当持有锁的时间相对较长或者请求锁的平均时间间隔较长,应该使用公平锁。在这些情况下,插队带来的吞吐量提升(当锁处于可用状态时,线程却还处于被唤醒的过程中)可能不会出现。

lock 默认公平锁还是非公平锁?公平锁是如何定义?如何实现的更多相关文章

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

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

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

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

  3. java里的锁总结(synchronized隐式锁、Lock显式锁、volatile、CAS)

    一.介绍 首先, java 的锁分为两类: 第一类是 synchronized 同步关键字,这个关键字属于隐式的锁,是 jvm 层面实现,使用的时候看不见: 第二类是在 jdk5 后增加的 Lock ...

  4. MySQL在默认事务下各SQL语句使用的锁分析

    数据库使用锁是为了支持更好的并发,提供数据的完整性和一致性.InnoDB是一个支持行锁的存储引擎,锁的类型有:共享锁(S).排他锁(X).意向共享(IS).意向排他(IX).为了提供更好的并发,Inn ...

  5. setdeamon 设置 线程为守护线程, (lock线程锁, BoundedSemaphore,rlock递归锁 ) 三种锁

    1.setdeamon 当主程序执行完时,子程序自动被销毁 ,内存自动被收回 例一: import threading, time def run(n): print('run %s'%n) time ...

  6. MySQL的默认隔离级别的实现依赖于MVCC和锁,准确点说就是一致性读和锁。

    MySQL的默认隔离级别的实现依赖于MVCC和锁,准确点说就是一致性读和锁.

  7. 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!

    网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...

  8. 写文章 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!

    网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...

  9. 偏向锁,偏向线程id ,自旋锁

    理解锁的基础知识 如果想要透彻的理解Java锁的来龙去脉,需要先了解以下基础知识. 基础知识之一:锁的类型 锁从宏观上分类,分为悲观锁与乐观锁. 乐观锁 乐观锁是一种乐观思想,即认为读多写少,遇到并发 ...

随机推荐

  1. 20155339 2016-2017-2 《Java程序设计》第十周学习总结

    20155339 2016-2017-2 <Java程序设计>第十周学习总结 教材学习内容总结 计算机网络概述 在计算机网络中,现在命名IP地址的规定是IPv4协议,该协议规定每个IP地址 ...

  2. 20145209 实验三 《敏捷开发与XP实践》 实验报告

    20145209 实验三 <敏捷开发与XP实践> 实验报告 实验内容 XP基础. XP核心实践. 相关工具. 实验步骤 敏捷开发与XP 1.敏捷开发 敏捷开发(Agile Developm ...

  3. echarts x轴文字换行显示

    xAxis : [ { splitLine:{show:false}, type : 'category', data : ['社交人际','沟通交流','心理认知','游戏玩耍','大小运动','生 ...

  4. WPF设置ListBoxItem失去焦点时的背景色

    <!--全局ListBoxItem--> <Style TargetType="ListBoxItem"> <Style.Resources> ...

  5. python 多线程笔记(2)-- 锁

    锁是什么?什么场合使用锁? 锁是一种机制,用于保护那些会引起冲突的资源. 比如上厕所,进去之后第一件事干嘛?把厕所门反锁!表示什么呢?表示这个厕所正在使用中! 至于在厕所里面干大事.干小事.还是打飞机 ...

  6. day 6 汽车4S店铺

    1.版本1:大框架 class CarStore(object): '''定义一个汽车店铺类''' pass class Car(object): '''定义一个汽车类''' pass car_sto ...

  7. Yii 2.0 使用验证码

    Yii2.0 提供了验证码组件.调用起来比较方便.以登录页面添加验证码为例. 1. 模型中添加字段和验证规则. common\models\LoginForm 添加如下代码 public $captc ...

  8. Sqlite数据多表联合update

    其实在Mysql中,多表联合update不是什么难事. 语法: 1 UPDATE table_references SET col_name1=expr1 [, col_name2=expr2 ... ...

  9. Python小白学习之函数装饰器

    装饰器 2018-10-25 13:49:37 装饰器从字面意思就是用来装饰的,在函数可以理解为:在函数中,我们不想影响原来的函数功能,又想给函数添加新的功能,这时候我们就用到了装饰器. 一般函数操作 ...

  10. HTTP结构讲解——《HTTP权威指南》系列

    HTTP结构 第二部分的5章主要介绍了HTTP服务器,代理,缓存,网关和机器人应用程序,这些都是Web系统架构的构造模块. Web服务器 第五章 Web服务器会对HTTP请求进行处理并提供响应.术语& ...