JUC.Condition学习
目录
I.初始化状态 II.await()操作 III.signal()操作
Condition的数据结构
线程何时阻塞和释放
await()方法
signal()和signalAll()方法
JUC提供了Lock可以方便的进行锁操作,但是有时候我们也需要对线程进行条件性的阻塞和唤醒,这时我们就需要condition条件变量,它就像是在线程上加了多个开关,可以方便的对持有锁的线程进行阻塞和唤醒。
Condition的概念
Condition实质上是被绑定到一个锁上。
大体实现流程


3个主要方法
Condition的数据结构
线程何时阻塞和释放
await方法
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public final void await() throws InterruptedException {
// 1.如果当前线程被中断,则抛出中断异常 if (Thread.interrupted()) throw new InterruptedException(); // 2.将节点加入到Condition队列中去,这里如果lastWaiter是cancel状态,那么会把它踢出Condition队列。 Node node = addConditionWaiter(); // 3.调用tryRelease,释放当前线程的锁 long savedState = fullyRelease(node); int interruptMode = 0; // 4.为什么会有在AQS的等待队列的判断? // 解答:signal操作会将Node从Condition队列中拿出并且放入到等待队列中去,在不在AQS等待队列就看signal是否执行了 // 如果不在AQS等待队列中,就park当前线程,如果在,就退出循环,这个时候如果被中断,那么就退出循环 while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } // 5.这个时候线程已经被signal()或者signalAll()操作给唤醒了,退出了4中的while循环 // 自旋等待尝试再次获取锁,调用acquireQueued方法 if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); } |
signal和signalAll方法
await*()清楚了,现在再来看signal/signalAll就容易多了。按照signal/signalAll的需求,就是要将Condition.await*()中FIFO队列中第一个Node唤醒(或者全部Node)唤醒。尽管所有Node可能都被唤醒,但是要知道的是仍然只有一个线程能够拿到锁,其它没有拿到锁的线程仍然需要自旋等待,就上上面提到的第4步(acquireQueued)。
|
1
2 3 4 5 6 7 |
public final void signal() {
if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first); } |
这里先判断当前线程是否持有锁,如果没有持有,则抛出异常,然后判断整个condition队列是否为空,不为空则调用doSignal方法来唤醒线程,看看doSignal方法都干了一些什么:
|
1
2 3 4 5 6 7 8 |
private void doSignal(Node first) {
do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null); } |
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
final boolean transferForSignal(Node node) {
/* * 设置node的waitStatus:Condition->0 */ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; /* |
|
1
2 3 4 5 6 7 8 9 |
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null); } |
这个方法就相当于把Condition队列中的所有Node全部取出插入到等待队列中去。
Condition应用示例:生产者和消费者
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。在最后我们来看一个应用示例
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
/**
* 生产者、消费者示例 */ public class ConditionTest { private int storage; private int putCounter; private int getCounter; private Lock lock = new ReentrantLock(); private Condition putCondition = lock.newCondition(); private Condition getCondition = lock.newCondition(); public void put() throws InterruptedException { public void get() throws InterruptedException { public class PutThread extends Thread { public class GetThread extends Thread { public static void main(String[] args) { |
JUC.Condition学习的更多相关文章
- JUC.Condition学习笔记[附详细源码解析]
目录 Condition的概念 大体实现流程 I.初始化状态 II.await()操作 III.signal()操作 3个主要方法 Condition的数据结构 线程何时阻塞和释放 await()方法 ...
- JUC——检视阅读
JUC--检视阅读 参考资料 JUC知识图参考 JUC框架学习顺序参考 J.U.C学习总结参考,简洁直观 易百并发编程,实践操作1,不推荐阅读,不及格 JUC文章,带例子讲解,可以学习2 Doug L ...
- JUC之线程间的通信
线程通信 视频1: 2021.12.18 JUC视频学习片段 对上次多线程编程步骤补充(中部): 创建资源类,在资源类中创建属性和操作方法 在资源类里面操作 判断 干活 通知 创建多个线程,调用资源类 ...
- Condition线程通信(七)
前言:对于线程通信,使用synchronized时使用wait.notify和notifyAll来实行线程通信.而使用Lock如何处理线程通信呢?答案就是本片的主角:Condition. 一.Cond ...
- 你知道什么是JUC了吗?
多线程一直Java开发中的难点,也是面试中的常客,趁着还有时间,打算巩固一下JUC方面知识,我想机会随处可见,但始终都是留给有准备的人的,希望我们都能加油!!! 沉下去,再浮上来,我想我们会变的不一样 ...
- day-4 python多进程编程知识点汇总
1. python多进程简介 由于Python设计的限制(我说的是咱们常用的CPython).最多只能用满1个CPU核心.Python提供了非常好用的多进程包multiprocessing,他提供了一 ...
- 我们一起来回顾一下Synchronized关键字吧
多线程一直Java开发中的难点,也是面试中的常客,趁着还有时间,打算巩固一下JUC方面知识,我想机会随处可见,但始终都是留给有准备的人的,希望我们都能加油!!! 沉下去,再浮上来,我想我们会变的不一样 ...
- 学习JUC源码(3)——Condition等待队列(源码分析结合图文理解)
前言 在Java多线程中的wait/notify通信模式结尾就已经介绍过,Java线程之间有两种种等待/通知模式,在那篇博文中是利用Object监视器的方法(wait(),notify().notif ...
- JUC.Lock(锁机制)学习笔记[附详细源码解析]
锁机制学习笔记 目录: CAS的意义 锁的一些基本原理 ReentrantLock的相关代码结构 两个重要的状态 I.AQS的state(int类型,32位) II.Node的waitStatus 获 ...
随机推荐
- openSUSE 安装
https://lug.ustc.edu.cn/sites/opensuse-guide/installation.php 开始 1. 简介2. 改用 GNU/Linux3. 获取 openSUSE4 ...
- SignalR的实时高频通讯
SignalR的实时高频通讯 第五章SignalR的实时高频通讯 概述:本例子演示了如果创建一个对象与其他浏览器共享实时状态的应用程序.我们要创建的应用程序为“MoveShape”,该MoveShap ...
- 网站静态化处理—web前端优化—上
网站静态化处理—web前端优化—上(11) 网站静态化处理这个系列马上就要结束了,今天我要讲讲本系列最后一个重要的主题web前端优化.在开始谈论本主题之前,我想问大家一个问题,网站静态化处理技术到底是 ...
- MVC 5 Scaffolding多层架构代码生成向导开源项目
asp.net MVC 5 Scaffolding多层架构代码生成向导开源项目(邀请你的参与) Visual Studio.net 2013 asp.net MVC 5 Scaffolding代码 ...
- 客户端javascript
<script> function moveon(){ var answer=confirm("hello,good morning!");//通过弹出对话框询问用户 ...
- SVN:One or more files are in a conflicted state
解决代码冲突 如果commit时出现"You have to update your work copy first."红色警告,说明版本库中的此文件已经被其他人修改了. 请先点& ...
- navicat连接oracle一个错误:ORA-12737 Instant Client Light:unsupported server character set ZHS16GBK
今天使用Navicat连接Oracle数据库.它报告了以下错误:"ORA-12737 Instant Client Light:unsupported server character se ...
- PHP 6:PHP 基本数据类型
原文:PHP 6:PHP 基本数据类型 本章将介绍PHP基本类型.相信我们已经熟悉了C/C++,C#或者Java里的任意一种语言.本章会以C#为比较语言.OK,如果你想学PHP,你最先考虑的是什么呢? ...
- PDF解决方案(1)--文件上传
相关专题链接 PDF解决方案(1)--文件上传 PDF解决方案(2)--文件转PDF PDF解决方案(3)--PDF转SWF PDF解决方案(4)--在线浏览 前言:最近参与了一个项目,客户要求把系统 ...
- 使用Visual Studio 2010 - 初学者系列 - 学习者系列文章
本文介绍Visual Studio 2010的基本使用. 1. 欢迎界面 2. 进入界面 3.选择菜单中的项目 4.选择项目路径,还有空白解决方案 5.选择 新建解决方案文件夹 6.选择新建项目 ...
