ReentrantLock基于Sync内部类来完成锁。Sync有两个不同的子类NonfairSync和FairSync。Sync继承于AbstractQueuedSynchronizer。

ReentrantLock的大部分方法都是基于AbstractQueuedSynchronizer实现,大部分仅仅是对AbstractQueuedSynchronizer的转发。因此,了解AbstractQueuedSynchronizer就非常重要。

作为AbstractQueuedSynchronizer的实现者需要实现isHeldExclusively,tryAcquire,tryRelease,(可选tryAcquireShared,tryReleaseShared)

那么我们看看对于一个常用的套路,ReentrantLock是如何实现同步的

for(int j=0;j<10000000;j++){
lock.lock();
try{
i++;
}finally {
lock.unlock();
}
}

lock.lock()内部实现为

public void lock() {
sync.lock();
}

我们先看一下Sync和NonfairSync的实现。

abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L; /**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock(); /**
* 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();
int c = getState();
     //如果没有锁上,则设置为锁上并设置自己为独占线程
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
     //如果锁上了,而且独占线程是自己,那么重新设置state+1,并且返回true
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
     //否则返回false
return false;
} protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != www.97yingyuan.org getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
} protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
} final ConditionObject newCondition() {
return new ConditionObject();
} // Methods relayed from outer class final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
} final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
} final boolean isLocked() {
return getState() != 0;
} /**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L; /**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
//如果没有人锁上,那么就设置我自己为独占线程,否则再acquire一次
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//调用到了AQS的acquire里面
acquire(1);
} protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}

上面的代码中,调用了AQS的acquire。下面看一下AQS的实现

    public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}

对于非公平的锁,tryAcquire会调用到NonfairSync里面的tryAcquire,而tryAcquire又会调用到Sync的nonfairTryAcquire。

addWaiter方法用于创建一个节点(值为当前线程)并维护一个双向链表。注意head是一个假节点,97影院 阻塞的节点是作为head后面的节点出现的。

    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;
} 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;
}
}
}
}
 
    final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}

Java多线程框架源码阅读之---ReentrantLock的更多相关文章

  1. Java多线程——ReentrantReadWriteLock源码阅读

    之前讲了<AQS源码阅读>和<ReentrantLock源码阅读>,本次将延续阅读下ReentrantReadWriteLock,建议没看过之前两篇文章的,先大概了解下,有些内 ...

  2. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  3. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

  4. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  5. CI框架源码阅读笔记2 一切的入口 index.php

    上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...

  6. 【java集合框架源码剖析系列】java源码剖析之TreeSet

    本博客将从源码的角度带领大家学习TreeSet相关的知识. 一TreeSet类的定义: public class TreeSet<E> extends AbstractSet<E&g ...

  7. 【java集合框架源码剖析系列】java源码剖析之HashSet

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于HashSet的知识. 一HashSet的定义: public class HashSet&l ...

  8. 【java集合框架源码剖析系列】java源码剖析之TreeMap

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于TreeMap的知识. 一TreeMap的定义: public class TreeMap&l ...

  9. 【java集合框架源码剖析系列】java源码剖析之ArrayList

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 本博客将从源码角度带领大家学习关于ArrayList的知识. 一ArrayList类的定义: public class Arr ...

随机推荐

  1. JavaScript中函数对象和对象的区别

    function Test (word) { console.log (word); } Test('哈哈,我是函数'); new Test('哈哈,我是对象'); //将以上的调用方式换种通俗易懂的 ...

  2. Linux下使用crontab命令配置定时任务

    一.语法结构 crontab [-e [UserName]|-l [UserName]|-r [UserName]|-v [UserName]|File ] 说明 : crontab 是用来让使用者在 ...

  3. SharePoint 2010 缺少站点保存为模板选项

    如果您尝试在SharePoint Server 2010中保存网站,并且没有看到"将网站另存为模板"选项,则可能是因为该网站已启用发布功能.如果使用站点发布功能,则有几个选项可将网 ...

  4. HTML之基本语法(链接标签、路径的介绍和使用)

    一.链接标签 语法:<a href="目标地址">这个标签上展示的内容</a> 作用:可以实现在当前页面跳转到新页面的操作 属性 1.target这个属性可 ...

  5. 使用Python生成ASCII字符画

    使用Python生成ASCII字符画 在很多的网站主页中或者程序的注释中会有一些好看的字符注释画.显得很牛逼的样子 例如: 知乎 _____ _____ _____ _____ /\ \ /\ \ / ...

  6. 【转】Popclip的JSON格式化扩展

    http://liuyunclouder.github.io/2016/09/29/JSONizer:Popclip的JSON格式化扩展 作为一个MAC党,不好好利用MAC的神兵利器,简直就是罪过.A ...

  7. java基础—方法重载(overload)

    一.方法的重载 方法名一样,但参数不一样,这就是重载(overload). 所谓的参数不一样,主要有两点:第一是参数的个数不一样,第二是参数的类型不一样.只要这两方面有其中的一方面不一样就可以构成方法 ...

  8. mac 使用homebrew 安装mysql

    1. 安装homebrew ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)" brew update ...

  9. 理解JS闭包的几个小实验

    学了JavaScript有一段时间了,但是对闭包还是不太理解,于是怀着心中的疑问做了几个小实验,终于有点明白了. 首先看一下MDN上的定义:闭包是函数和声明该函数的词法环境的组合. 简单来说,闭包是一 ...

  10. 【树形dp】bzoj4726: [POI2017]Sabota?

    找点概率期望的题做一做 Description 某个公司有n个人, 上下级关系构成了一个有根树.其中有个人是叛徒(这个人不知道是谁).对于一个人, 如果他 下属(直接或者间接, 不包括他自己)中叛徒占 ...