ReentrantLock 实现:  

我们主要看一下非公平锁的实现:

    /**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
    //cas 原子性操作,将state 状态改变为1
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());//返回true ,说明目前现在还没有线程进来,那么就将当前的线程标记为锁的线程
else
        //否则的话,执行如下逻辑
acquire(1);
}

执行如下方法(包含了主要的3个方法): tryAcquire       addWaiter       acquireQueued

 public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
 protected final boolean tryAcquire(int acquires) {
    //非公平锁实现
return nonfairTryAcquire(acquires);
}
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
        //获取当前state 的值这个值表示当前锁被重入的次数
int c = getState();
if (c == 0) {
          //如果=0,表示当前锁还未被占用
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");
        //标记state ,重入的次数
setState(nextc);
return true;
}
      //表示线程未申请到锁
return false;
}

在线程未申请到锁的时候:会执行  addWaiter       acquireQueued 这两个方法:

private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
      //预先处理下,解决性能问题
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}

我们主要看一下如何将线程安全同步的加入到队列中: 如下典型的乐观锁的实现:cas +for 循环重试机制

private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}

完成了加入队列的操作后接下来就是 acquireQueued 操作了

final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
    //循环阻塞
for (;;) {
final Node p = node.predecessor();
        //如果当前node 节点的上一个节点是head 以及state 状态=0 时候(有线程释放锁的时候)
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
            //唯一出口
return interrupted;
}
        //线程park 阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}

ReentrantLock 实现的更多相关文章

  1. Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)

    AbstractQueuedSynchronizer是实现Java并发类库的一个基础框架,Java中的各种锁(RenentrantLock, ReentrantReadWriteLock)以及同步工具 ...

  2. 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock

    ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...

  3. 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析

    前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获 ...

  4. 【Java并发编程实战】-----“J.U.C”:ReentrantLock之二lock方法分析

    前一篇博客简单介绍了ReentrantLock的定义和与synchronized的区别,下面跟随LZ的笔记来扒扒ReentrantLock的lock方法.我们知道ReentrantLock有公平锁.非 ...

  5. 【Java并发编程实战】-----“J.U.C”:ReentrantLock之一简介

    注:由于要介绍ReentrantLock的东西太多了,免得各位客官看累,所以分三篇博客来阐述.本篇博客介绍ReentrantLock基本内容,后两篇博客从源码级别分别阐述ReentrantLock的l ...

  6. java线程 公平锁 ReentrantLock(boolean fair)

    一.公平锁 1.为什么有公平锁 CPU在调度线程的时候是在等待队列里随机挑选一个线程,由于这种随机性所以是无法保证线程先到先得的(synchronized控制的锁就是这种非公平锁).但这样就会产生饥饿 ...

  7. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

    本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...

  8. 【JUC】JDK1.8源码分析之ReentrantLock(三)

    一.前言 在分析了AbstractQueuedSynchronier源码后,接着分析ReentrantLock源码,其实在AbstractQueuedSynchronizer的分析中,已经提到过Ree ...

  9. Lock、ReentrantLock、synchronized、ReentrantReadWriteLock使用

    先来看一段代码,实现如下打印效果: 1 2 A 3 4 B 5 6 C 7 8 D 9 10 E 11 12 F 13 14 G 15 16 H 17 18 I 19 20 J 21 22 K 23 ...

  10. java分析源码-ReentrantLock

    一.前言 在分析了 AbstractQueuedSynchronier 源码后,接着分析ReentrantLock源码,其实在 AbstractQueuedSynchronizer 的分析中,已经提到 ...

随机推荐

  1. 打造高效的工作环境 – SHELL 篇

    注:本文由雷俊(Javaer/Emacser)和我一起编辑,所以文章版权归雷俊与我共同所有,转载者必需注明出处和我们两位作者.原文最早发于酷壳微信公众号,后来我又做了一些修改,再发到博客这边. 程序员 ...

  2. spark-rpc是如何实现将netty的Channel隐藏在inbox中的

    class TransportServer bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Overri ...

  3. Mock及Mockito使用

    mockito http://www.vogella.com/tutorials/Mockito/article.html 原文地址: http://www.open-open.com/lib/vie ...

  4. mongo 数据查询

    基本查询 方法find():查询 db.集合名称.find({条件文档}) 方法findOne():查询,只返回第一个 db.集合名称.findOne({条件文档}) 方法pretty():将结果格式 ...

  5. 【python】django上传文件

    参考:https://blog.csdn.net/zahuopuboss/article/details/54891917 参考:https://blog.csdn.net/zzg_550413470 ...

  6. Opencv与Qt (一)之运行测试读取图片

    刚刚在vs上装好了QT和Opencv,试一下效果把. 我简单的创建了一个label,然后使用Opencv导入图像,因为Opencv导入图像是MAT格式的,在使用Qt的时候我们要把导入的图像转换成Qim ...

  7. MSMQ 队列消息和死信队列

    日志消息 日志队列可以保存你操作过的消息的备份.它的好处是,一但发现前面的操作失败,可以从日志队列中重新创建出原先的消息对象,然后再进行操作. 例如,向远方发送一个消息对象,然后对方返回一个失败的确认 ...

  8. 微信小程序中把页面生成图片

    这个问题我上网搜了一下,答案有多种,但是真正能用的没有几何.很多答案都是雷同,有的网友也不负责任,直接拿来照抄,自己也不跑一遍看看.哎,不说了,说多了全是泪.希望我们的技术达人在分享的时候,能够真实的 ...

  9. DP问题

    1.背包问题

  10. 使用 nodeJs 开发微信公众号(获取access_token)

    要使用微信提供的功能接口,就需要获取到access_token,这是开发公众号必不可少的一部 access_token有效期20分钟,建议保存起来,过期后在重新获取 获取流程如下: 我将微信相关的操作 ...