继续之前文章。
无论是HashMap,LinkedHashMap,ArrayList等都是非线程安全的,在并发情况下会出现问题,而Jdk也提供了concurrent包,该包下边主要是关于线程安全相关的类,例如ConcurrentHashMap,ConcurrentHashMap的实现原理不在这里阐述了,这里主要讲解跟它有关的锁问题ReentrantLock(重入锁),CAS(比较与交换)

ReentrantLock

  1. 说明
    分为公平锁和非公平锁两个都继承内部类Sync,各自实现,而构造方法也可以指定实例化时采用公平锁还是非公平锁。
  • 公平锁:会按照请求的顺序获取锁,如果锁已经被占用,则新来的请求放到队列中。
  • 非公平锁:不是按照请求顺序获取锁,存在插队现象。
  1. 类的结构
//内部类
private final Sync sync;
//定义了内部类
abstract static class Sync extends AbstractQueuedSynchronizer
//非公平锁继承内部类
static final class NonfairSync extends Sync
//公平锁继承内部类
static final class FairSync extends Sync
  1. ReentrantLock构造方法有两个:无参和有参(指定采用公平和非公平)
    分别看下是如何初始化的。
public ReentrantLock() {//默认非公平锁sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {//若fair为true,则是公平锁,否则非公平锁sync = fair ? new FairSync() : new NonfairSync();}
  1. 接下来看下公平锁lock()是如何实现加锁的
public void lock() {//根据实例化的锁走对应的子类实现sync.lock();
}
//公平锁
final void lock() {//调用父类AbstractQueuedSynchronizer中的方法acquire(1);}public final void acquire(int arg) {//tryAcquire子类重新了所以调用子类,尝试获取锁,若能获取到直接返回if (!tryAcquire(arg) &&//获取不到则直接加入到等待队列中acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();
}protected final boolean tryAcquire(int acquires) {//获取当前线程final Thread current = Thread.currentThread();//获取状态,获取状态0int c = getState();if (c == 0) {//判断队列中是否有比自己优先级更高的线程,若没有则通过CAS获取锁if (!hasQueuedPredecessors() &&//通过CAS获取锁,具体如何获取后面说compareAndSetState(0, acquires)) {//设置自己持有锁,并返回truesetExclusiveOwnerThread(current);return true;}}//若当前持有锁的线程是自己,则将重入次数累加else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");//设置新的状态,并返回truesetState(nextc);return true;}return false;
}
//上边代码中的hasQueuedPredecessors
public final boolean hasQueuedPredecessors() {//Node包含下个线程和上个线程,采用这种方式形成一个链表//Node中有等待状态waitStatus,前节点prev,下一个节点next及当前线程thread,//下一个等待线程nextWaiterNode t = tail; // Read fields in reverse initialization orderNode h = head;Node s;//判断是否有等待获取锁的节点return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());
}

公平锁的过程是:
首先尝试获取锁,获取锁的过程中会判断队列中是否有比自己优先级高的线程若有则返回false,加锁失败,若没有则通过CAS获取锁,并设置自己为当前持有锁的线程,返回true;
若是重入则次数加1,并返回true;若获取不到所则将自己加到队列中等待获取锁。
5. 非公平锁,会有插队的现象,导致这中现象是因为每次lock都会先获取锁,不会检查队列中是否包含等待线程,若获取到则插队成功,否则失败添加到队列中。

final void lock() {//采用CAS方式,若获取到则设置自己为所的持有者否则按照公平锁的方式请求。if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}
  1. tryLock() 尝试获取锁,获取到就返回true,否则失败false
public boolean tryLock() {return sync.nonfairTryAcquire(1);
}
//与公平锁有点类似
final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {//与公平锁不同之处,不判断队列,直接通过CAS方式获取锁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;}
  1. tryLock(long timeout, TimeUnit unit)指定等待时间,到时还未获取到锁则返回false。
public boolean tryLock(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public final boolean tryAcquireNanos(int arg, long nanosTimeout)throws InterruptedException {//若线程中断则返回异常if (Thread.interrupted())throw new InterruptedException();//tryAcquire尝试获取锁,非公平和公平各自实现,可以看上边代码return tryAcquire(arg) ||doAcquireNanos(arg, nanosTimeout);
}

CAS

在ReentrantLock中核心部分采用的还是CAS(比较与交换,Compare and swap)获取锁,CAS是CPU的指令,意思是“认为val的值是1,如果是1则将val的值更新为2,否则不做更改,并返回V实际的值”。

先介绍到这里有什么不妥之处也请看到的大咖纠正。

也可以关注公众号进行探讨

ReentrantLock与CAS相关推荐

  1. 在竞争激烈的情况下,ReentrantLock与CAS的性能比较

    这次看了源码,发现ReentrantLock的底层实现是AQS,而AQS底层实现是Volatile+CAS+CLH队列,因此想看看ReentrantLock与CAS的性能比较,因此做了这么一组实验. ...

  2. JUC:ReentrantLock互斥锁

    JUC:ReentrantLock 关键词 公平锁和非公平锁:ReentrantLock(CAS+AQS队列) 公平锁和非公平锁的变量 private final Sync sync;(核心) try ...

  3. 一线互联网常见的14个Java面试题,你颤抖了吗程序员

    跳槽不算频繁,但参加过不少面试(电话面试.face to face面试),面过大/小公司.互联网/传统软件公司,面糊过(眼高手低,缺乏实战经验,挂掉),也面过人,所幸未因失败而气馁,在此过程中不断查缺 ...

  4. java锁的有哪些_「并发编程」Java锁分类和特点有哪些

    公平锁.非公平锁:公平锁指多个线程按照申请锁的顺序来获取锁,非公平锁就是没有顺序完全随机,所以能会造成优先级反转或者饥饿现象:synchronized 就是非公平锁,ReentrantLock(使用 ...

  5. RocketMQ Broker的最佳实践

    RocketMQ Broker的最佳实践 翻译自rocket官方文档 Broker Role Broker的方式有异步主,同步主,或者从.如果不能容忍消息丢失,建议以同步主从方式部署.如果对丢失没那么 ...

  6. JAVA后端面试100 QA之第一篇

    转载自  JAVA后端面试100 Q&A之第一篇 1. synchronized和reentrantlock异同 相同点 都实现了多线程同步和内存可见性语义 都是可重入锁 不同点 实现机制不同 ...

  7. java 锁_Java之线程并发的各种锁、锁、锁

    因为两周没更新了... 也不是懒,这两周确实有些忙,赶项目进度赶的不亦乐乎... 终于赶在工期前,可以进入内测了,我也有了些时间,可以更新啦... 线程并发锁是很常见的问题,而且在Java中锁的类型. ...

  8. 最全的BAT大厂面试题整理,系列篇

    前言 看到一篇文章中提到"最近几年国内的初级Android程序员已经很多了,但是中高级的Android技术人才仍然稀缺",这的确不假,从我在百度所进行的一些面试来看,找一个适合的高 ...

  9. 一线互联网常见的14个Java面试题,你颤抖了吗程序员...

    跳槽不算频繁,但参加过不少面试(电话面试.face to face面试),面过大/小公司.互联网/传统软件公司,面糊过(眼高手低,缺乏实战经验,挂掉),也面过人,所幸未因失败而气馁,在此过程中不断查缺 ...

最新文章

  1. java中的类修饰符、成员变量修饰符、方法修饰符。
  2. Docker环境配置指南!
  3. android 获取短信验证码倒计时
  4. BIEE汇总数据如何放在后面
  5. 如何关闭SAP Fiori的病毒扫描设置
  6. 基于MTD的NAND驱动开发(二)
  7. 转]Linux杀死进程方法大全
  8. DOM——获取元素的方式
  9. 探究.NET的bin引用程序集运行机制看.NET程序集部署原理
  10. input之question
  11. 史上最详细的宝塔部署java项目流程
  12. html如何生成条形码,前端使用JsBarcode生成条形码
  13. 虚拟机红帽子php,virtualbox新建redhat9.0(红帽子linux)系统
  14. 解决华为安全键盘收回, 软键盘位置没收回的问题
  15. 【全局路径规划】A*算法 A* Search Algorithm
  16. HEVC学习笔记(二)整体介绍
  17. CodeBlocks出现不支持16位应用程序 360解决方法 已经失效(2019-11-22)
  18. PMP——项目管理介绍
  19. 微信公众号打开的h5网页点击按钮返回公众号
  20. 华为AR路由器镜像端口配置及取消配置

热门文章

  1. 英语中美音与英音的区别与选择
  2. 英式英语VS美式英语的差异
  3. 互联网学习(三):基于TCP协议的HTTP协议
  4. IT界牛逼的人之一:法布里斯·贝拉
  5. 微信小程序API 数据缓存
  6. 为何是贵州?中国“数据中心之都”崛起之谜
  7. Elasticsearch8系列【1】概述
  8. 2021 HW 漏洞清单汇总 ( 附 poc )
  9. 真正的“区块链手机”可以做到这5件事
  10. RIME中州韵输入法如何实现中英文翻译功能