java 语言中谈到锁,少不了比较一番 synchronized 和 ReentrantLock 的原理,本文不作分析,只是简单介绍一下 ReentrantLock 的用法,从使用中推测其内部的一些原理。

代码示例:

public static void main(String[] args) throws InterruptedException {
final ReentrantLock lock = new ReentrantLock();
final Condition con1 = lock.newCondition();
final Condition con2 = lock.newCondition(); // lock.lock(); Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
con1.await();
System.out.println("wake from cond1");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
});
t1.start(); Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
con2.await();
System.out.println("wake from cond2");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
});
t2.start(); Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
con2.await();
System.out.println("wake from cond2");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
});
t3.start(); Thread.sleep(100);
try {
lock.lock();
System.out.println("lock.getQueueLength() = " + lock.getQueueLength());
System.out.println("lock.getWaitQueueLength(con1) = " + lock.getWaitQueueLength(con1));
System.out.println("lock.getWaitQueueLength(con2) = " + lock.getWaitQueueLength(con2));
con1.signal();
con2.signalAll(); Thread.sleep(100);
System.out.println("lock.getWaitQueueLength(con1) = " + lock.getWaitQueueLength(con1));
System.out.println("lock.getWaitQueueLength(con2) = " + lock.getWaitQueueLength(con2));
} finally {
lock.unlock();
} }

lock 和 await 会改变 state 的值。

以 ReentrantLock.getQueueLength 和 ReentrantLock.getWaitQueueLength 作为入口:前者作用是返回获取锁失败,处于等待状态的线程个数,后者是返回等待某一个 condition 的线程个数。

// int java.util.concurrent.locks.ReentrantLock.getQueueLength()
public final int getQueueLength() {
return sync.getQueueLength();
} // int java.util.concurrent.locks.AbstractQueuedSynchronizer.getQueueLength()
public final int getQueueLength() {
int n = 0;
for (Node p = tail; p != null; p = p.prev) {
if (p.thread != null)
++n;
}
return n;
}

很简单,就是遍历阻塞线程的链表。

// int java.util.concurrent.locks.ReentrantLock.getWaitQueueLength(Condition condition)
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
} // int java.util.concurrent.locks.AbstractQueuedSynchronizer.getWaitQueueLength(ConditionObject condition)
public final int getWaitQueueLength(ConditionObject condition) {
if (!owns(condition))
throw new IllegalArgumentException("Not owner");
return condition.getWaitQueueLength();
} // int java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject.getWaitQueueLength()
protected final int getWaitQueueLength() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int n = 0;
for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
if (w.waitStatus == Node.CONDITION)
++n;
}
return n;
}

同样,也是遍历链表,不同的是,这是 Condition 的链表。

现在,我们知道,ReentrantLock 中有 2 种不同的链表,其一是阻塞线程,其二是 Condition 等待链表,2 种链表都是使用 Node:

// java.util.concurrent.locks.AbstractQueuedSynchronizer.Node
static final class Node {
static final Node EXCLUSIVE = null;
// 线程阻塞节点的状态
static final int CANCELLED = 1;
static final int SIGNAL = -1;
// condition 节点的状态
static final int CONDITION = -2;
static final int PROPAGATE = -3;
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
}

节点的类型表明链表的类型。

看看 Condition 实现类的 api:

public class ConditionObject implements Condition, java.io.Serializable {
private static final long serialVersionUID = 1173984872572414699L;
private transient Node firstWaiter;
private transient Node lastWaiter; /**
* Adds a new waiter to wait queue.
* @return its new wait node
*/
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
} public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
} /**
* Moves the longest-waiting thread, if one exists, from the
* wait queue for this condition to the wait queue for the
* owning lock.
*
* @throws IllegalMonitorStateException if {@link #isHeldExclusively}
* returns {@code false}
*/
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
}

在开头的示例中,创建了 2 个 Condition 对象,每个Condition 对象有一个自己的等待链表。

从使用角度看 ReentrantLock 和 Condition的更多相关文章

  1. Java多线程高并发学习笔记(二)——深入理解ReentrantLock与Condition

    锁的概念 从jdk发行1.5版本之后,在原来synchronize的基础上,增加了重入锁ReentrantLock. 本文就不介绍synchronize了,有兴趣的同学可以去了解一下,本文重点介绍Re ...

  2. Java多线程之ReentrantLock与Condition

    一.ReentrantLock 1.ReentrantLock简介 ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”.ReentrantLock 类实现了 Lock ,它拥有与 sy ...

  3. Java多线程之wait、notify/notifyAll 详解,用wait 和notifyAll 以及synchronized实现阻塞队列,多线程拓展之ReentrantLock与Condition

    前言:这几天看了很多关于多线程的知识,分享一波.(但是目前接触的项目还未用到过,最多用过线程池,想看线程池 请看我之前的博客) 关于基本的理论等 参考如下: https://www.cnblogs.c ...

  4. 使用 ReentrantLock 和 Condition 实现一个阻塞队列

    前言 从之前的阻塞队列的源码分析中,我们知道,JDK 中的阻塞队列是使用 ReentrantLock 和 Condition 实现了,我们今天来个简易版的.代码如下: 代码 public class ...

  5. java 多线程 19: ReentrantLock 与 Condition

    ReentrantLock ReentrantLock,一个可重入的互斥锁,它具有与使用synchronized方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大. Reentran ...

  6. Java多线程(九)之ReentrantLock与Condition

    一.ReentrantLock 类   1.1 什么是reentrantlock   java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 ...

  7. ReentrantLock 和 Condition的使用

    ReentrantLock  ReentrantLock可以等同于synchronized使用. ReentrantLock 类实现了Lock ,它拥有与 synchronized 相同的并发性和内存 ...

  8. 【转】使用者角度看bionic pthread_mutex和linux futex实现

    使用者角度看bionic pthread_mutex和linux futex实现 本文所大篇幅引用的参考文章主要描述针对glibc和pthread实现:而本文的考察代码主要是android的bioni ...

  9. Android IOS WebRTC 音视频开发总结(四八)-- 从商业和技术的角度看视频行业的机会

    本文主要从不同角度介绍视频行业的机会,文章来自博客园RTC.Blacker,支持原创,转载必须说明出处,欢迎关注个人微信公众号blacker ----------------------------- ...

随机推荐

  1. JavaScript深入

    BOM(浏览器对象模型)——与浏览器对话: Window对象(代表浏览器的窗口——不包括工具栏.滚动条): //所有全局对象.全局函数,均自动成为window对象的成员(document属于浏览器,所 ...

  2. Newtonsoft.Json 去掉\r\n

    itemKindList.ToString(Newtonsoft.Json.Formatting.None)

  3. snakemake使用笔记

    snakemake是一个用来编写任务流程的工具,用python编写的,因此其执行的流程脚本也比较通俗易懂,易于理解. 一.从一个简单的例子开始 1.安装snakemake 安装snakemake的方法 ...

  4. ISNULL函数的深入讲解

    1.  标题有点夸张 2. 今天做统计查询员工加班时长的时,因为要将NULL值导入到decimal类型的字段中,但是发现导入之后得字段不属于NULL也不等于0,因此在接下来的运算过程中就很难继续进行, ...

  5. link 和 import的区别

    二者区别: link属于html标签,而@import是css提供的. 页面被加载时,link因为是HTM标签, 把认会同时被加载,而@import引用的css会等到页面加载结束后加载. link是h ...

  6. leecode第十六题(最接近的三数之和)

    class Solution { public: void quick_order(vector<int>& num, int star, int en)//快排 { int st ...

  7. DEBUG(2)--函数的输入参数要做适当的检查

      今天在调试程序时发现,在单步运行的情况下,程序执行没有问题,但是直接运行就会出问题.出问题的代码如下 for(int col=0;col<=9;++col) { int killid=Pos ...

  8. ZOJ 3962 Seven Segment Display

    Seven Segment Display 思路: 经典数位dp 代码: #include<bits/stdc++.h> using namespace std; #define LL l ...

  9. Selenium WebDriver Api 知识梳理

    之前一直没有系统的梳理WebDriver Api的相关知识,今天借此机会整理一下. 1.页面元素定位 1.1.8种常用定位方法 # id定位 driver.find_element_by_id() # ...

  10. discuz的学习和部署

    1.http://jingyan.baidu.com/article/b87fe19eb57ff252183568d9.html 下载好后安装一个mysql, 2.