从使用角度看 ReentrantLock 和 Condition
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的更多相关文章
- Java多线程高并发学习笔记(二)——深入理解ReentrantLock与Condition
锁的概念 从jdk发行1.5版本之后,在原来synchronize的基础上,增加了重入锁ReentrantLock. 本文就不介绍synchronize了,有兴趣的同学可以去了解一下,本文重点介绍Re ...
- Java多线程之ReentrantLock与Condition
一.ReentrantLock 1.ReentrantLock简介 ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”.ReentrantLock 类实现了 Lock ,它拥有与 sy ...
- Java多线程之wait、notify/notifyAll 详解,用wait 和notifyAll 以及synchronized实现阻塞队列,多线程拓展之ReentrantLock与Condition
前言:这几天看了很多关于多线程的知识,分享一波.(但是目前接触的项目还未用到过,最多用过线程池,想看线程池 请看我之前的博客) 关于基本的理论等 参考如下: https://www.cnblogs.c ...
- 使用 ReentrantLock 和 Condition 实现一个阻塞队列
前言 从之前的阻塞队列的源码分析中,我们知道,JDK 中的阻塞队列是使用 ReentrantLock 和 Condition 实现了,我们今天来个简易版的.代码如下: 代码 public class ...
- java 多线程 19: ReentrantLock 与 Condition
ReentrantLock ReentrantLock,一个可重入的互斥锁,它具有与使用synchronized方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大. Reentran ...
- Java多线程(九)之ReentrantLock与Condition
一.ReentrantLock 类 1.1 什么是reentrantlock java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 ...
- ReentrantLock 和 Condition的使用
ReentrantLock ReentrantLock可以等同于synchronized使用. ReentrantLock 类实现了Lock ,它拥有与 synchronized 相同的并发性和内存 ...
- 【转】使用者角度看bionic pthread_mutex和linux futex实现
使用者角度看bionic pthread_mutex和linux futex实现 本文所大篇幅引用的参考文章主要描述针对glibc和pthread实现:而本文的考察代码主要是android的bioni ...
- Android IOS WebRTC 音视频开发总结(四八)-- 从商业和技术的角度看视频行业的机会
本文主要从不同角度介绍视频行业的机会,文章来自博客园RTC.Blacker,支持原创,转载必须说明出处,欢迎关注个人微信公众号blacker ----------------------------- ...
随机推荐
- 报名 | 蚂蚁金服ATEC科技大会 · 上海:数字金融新原力
小蚂蚁说: 2019年1月4日,蚂蚁金服ATEC城市峰会将以“数字金融新原力(The New Force of Digital Finance)”为主题,在中国上海举办.蚂蚁金服ATEC(Ant Te ...
- DataGrid的列上添加日期控件
今天的使用EasyUI datagrid的时候,遇到了如下问题,如下图:
- Ubuntu 追加组,用户,设置免sudo密码输入
1,以root权限执行groupadd命令创建dev组. sudo groupadd dev 2,用adduser命令创建bpuser用户,--ingroup指定用户加入dev组. sud ...
- idataway盐城
地点的经纬度.
- 第 3 章 镜像 - 019 - 使用公共 Registry
保存和分发镜像的最直接方法就是使用 Docker Hub.https://hub.docker.com/ Docker Hub 是 Docker 公司维护的公共 Registry.用户可以将自己的镜像 ...
- 通过cookies跳过验证码登陆页面,直接访问网站的其它URL
我每次手动访问去NN网的一家酒店,就不需要登陆,一旦我用脚本打开就会让我登陆,而登陆页面又有验证码,不想识别验证码,所以就想:“通过cookies跳过验证码登陆页面,直接访问网站的其它URL” 转 ...
- 关于 Oracle DB CONSTRAINT约束的一些SQL ORA-02292: integrity constraint violated
ALTER TABLE table_name DISABLE CONSTRAINT constraint_name; select * from all_constraints where owner ...
- Spring Boot设置值:分别用@ConfigurationProperties和@Value给属性设值及其区别
@ConfigurationProperties给属性映射值编写JavaBean/** 将配置文件application.properties中配置的每一个属性值映射到当前类的属性中:* @Confi ...
- for...in和for...of循环的区别
使用for...in和for...of分别对Array,Set,Map做测试 var a=["A","B","C"]; var b=new ...
- causal snps | causal variants | tensorflow | 神经网络实战 | Data Simulation
先读几篇文章: Interpretation of Association Signals and Identification of Causal Variants from Genome-wide ...