Condition介绍

Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。

不同的是,Object中的wait(),notify(),notifyAll()方法是和”同步锁”(synchronized关键字)捆绑使用的;而Condition是需要与”互斥锁”/”共享锁”捆绑使用的。

Condition的使用介绍

  • 示例1是通过Object的wait(), notify()来演示线程的休眠/唤醒功能。
  • 示例2是通过Condition的await(), signal()来演示线程的休眠/唤醒功能。

    示例1 2展示了两者的相似之处。

  • 示例3是通过Condition的高级功能

Object的wait,notify方法

public class WaitTest1 {public static void main(String[] args) {ThreadA ta = new ThreadA("ta");synchronized(ta) { // 通过synchronized(ta)获取“对象ta的同步锁”try {System.out.println(Thread.currentThread().getName()+" start ta");ta.start();System.out.println(Thread.currentThread().getName()+" block");ta.wait();    // 等待System.out.println(Thread.currentThread().getName()+" continue");} catch (InterruptedException e) {e.printStackTrace();}}}static class ThreadA extends Thread{public ThreadA(String name) {super(name);}public void run() {synchronized (this) { // 通过synchronized(this)获取“当前对象的同步锁”System.out.println(Thread.currentThread().getName()+" wakup others");notify();    // 唤醒“当前对象上的等待线程”}}}
}

Condition的await,signal方法

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class ConditionTest1 {private static Lock lock = new ReentrantLock();private static Condition condition = lock.newCondition();public static void main(String[] args) {ThreadA ta = new ThreadA("ta");lock.lock(); // 获取锁try {System.out.println(Thread.currentThread().getName()+" start ta");ta.start();System.out.println(Thread.currentThread().getName()+" block");condition.await();    // 等待System.out.println(Thread.currentThread().getName()+" continue");} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();    // 释放锁}}static class ThreadA extends Thread{public ThreadA(String name) {super(name);}public void run() {lock.lock();    // 获取锁try {System.out.println(Thread.currentThread().getName()+" wakup others");condition.signal();    // 唤醒“condition所在锁上的其它线程”} finally {lock.unlock();    // 释放锁}}}
}

从上面两个例子,我们可以看出来Object的notify,wait方法实际上用Condition一样可以实现。但是这就意味着两个东西一样吗?

它更强大的地方在于:能够更加精细的控制多线程的休眠与唤醒。对于同一个锁,我们可以创建多个Condition,在不同的情况下使用不同的Condition。

例如,假如多线程读/写同一个缓冲区:
当向缓冲区中写入数据之后,唤醒”读线程”;当从缓冲区读出数据之后,唤醒”写线程”;并且当缓冲区满的时候,”写线程”需要等待;当缓冲区为空时,”读线程”需要等待。

如果采用Object类中的wait(), notify(), notifyAll()实现该缓冲区,当向缓冲区写入数据之后需要唤醒”读线程”时,不可能通过notify()或notifyAll()明确的指定唤醒”读线程”,而只能通过notifyAll唤醒所有线程(但是notifyAll无法区分唤醒的线程是读线程,还是写线程)。

但是,通过Condition,就能明确的指定唤醒读线程。
看看下面的示例3,可能对这个概念有更深刻的理解。

Condition高级特性的例子:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;class BoundedBuffer {final Lock lock = new ReentrantLock();final Condition notFull  = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[5];int putptr, takeptr, count;public void put(Object x) throws InterruptedException {lock.lock();    //获取锁try {// 如果“缓冲已满”,则等待;直到“缓冲”不是满的,才将x添加到缓冲中。while (count == items.length)notFull.await();// 将x添加到缓冲中items[putptr] = x; // 将“put统计数putptr+1”;如果“缓冲已满”,则设putptr为0。if (++putptr == items.length) putptr = 0;// 将“缓冲”数量+1++count;// 唤醒take线程,因为take线程通过notEmpty.await()等待notEmpty.signal();// 打印写入的数据System.out.println(Thread.currentThread().getName() + " put  "+ (Integer)x);} finally {lock.unlock();    // 释放锁}}public Object take() throws InterruptedException {lock.lock();    //获取锁try {// 如果“缓冲为空”,则等待;直到“缓冲”不为空,才将x从缓冲中取出。while (count == 0) notEmpty.await();// 将x从缓冲中取出Object x = items[takeptr]; // 将“take统计数takeptr+1”;如果“缓冲为空”,则设takeptr为0。if (++takeptr == items.length) takeptr = 0;// 将“缓冲”数量-1--count;// 唤醒put线程,因为put线程通过notFull.await()等待notFull.signal();// 打印取出的数据System.out.println(Thread.currentThread().getName() + " take "+ (Integer)x);return x;} finally {lock.unlock();    // 释放锁}}
}public class ConditionTest2 {private static BoundedBuffer bb = new BoundedBuffer();public static void main(String[] args) {// 启动10个“写线程”,向BoundedBuffer中不断的写数据(写入0-9);// 启动10个“读线程”,从BoundedBuffer中不断的读数据。for (int i=0; i<10; i++) {new PutThread("p"+i, i).start();new TakeThread("t"+i).start();}}static class PutThread extends Thread {private int num;public PutThread(String name, int num) {super(name);this.num = num;}public void run() {try {Thread.sleep(1);    // 线程休眠1msbb.put(num);        // 向BoundedBuffer中写入数据} catch (InterruptedException e) {}}}static class TakeThread extends Thread {public TakeThread(String name) {super(name);}public void run() {try {Thread.sleep(10);                    // 线程休眠1msInteger num = (Integer)bb.take();    // 从BoundedBuffer中取出数据} catch (InterruptedException e) {}}}
}

运行结果:

p1 put  1
p4 put  4
p5 put  5
p0 put  0
p2 put  2
t0 take 1
p3 put  3
t1 take 4
p6 put  6
t2 take 5
p7 put  7
t3 take 0
p8 put  8
t4 take 2
p9 put  9
t5 take 3
t6 take 6
t7 take 7
t8 take 8
t9 take 9

说明:
(01) BoundedBuffer 是容量为5的缓冲,缓冲中存储的是Object对象,支持多线程的读/写缓冲。多个线程操作“一个BoundedBuffer对象”时,它们通过互斥锁lock对缓冲区items进行互斥访问;而且同一个BoundedBuffer对象下的全部线程共用“notFull”和“notEmpty”这两个Condition。

notFull用于控制写缓冲,notEmpty用于控制读缓冲。

当缓冲已满的时候,调用put的线程会执行notFull.await()进行等待;

当缓冲区不是满的状态时,就将对象添加到缓冲区并将缓冲区的容量count+1,最后,调用notEmpty.signal()缓冲notEmpty上的等待线程(调用notEmpty.await的线程)。

简言之,notFull控制“缓冲区的写入”,当往缓冲区写入数据之后会唤醒notEmpty上的等待线程。
同理,notEmpty控制“缓冲区的读取”,当读取了缓冲区数据之后会唤醒notFull上的等待线程。

JUC锁-Condition(三)相关推荐

  1. Java多线程系列---“JUC锁”01之 框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下: 01. Java多线程系列--"JUC锁"01之 框架 02. Java多线程系列--"JUC锁 ...

  2. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对"公平锁"的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括: 基本概念 ReentrantLock数据结构 参考代码 获取公平锁(基于JDK1.7.0 ...

  3. JUC锁框架AbstractQueuedSynchronizer详细分析

    转载自:https://www.jianshu.com/p/0da2939391cf AQS是JUC锁框架中最重要的类,通过它来实现独占锁和共享锁的.本章是对AbstractQueuedSynchro ...

  4. JUC锁框架_AbstractQueuedSynchronizer详细分析

    AQS是JUC锁框架中最重要的类,通过它来实现独占锁和共享锁的.本章是对AbstractQueuedSynchronizer源码的完全解析,分为四个部分介绍: CLH队列即同步队列:储存着所有等待锁的 ...

  5. JUC锁框架——AQS源码分析

    2019独角兽企业重金招聘Python工程师标准>>> JUC锁介绍 Java的并发框架JUC(java.util.concurrent)中锁是最重要的一个工具.因为锁,才能实现正确 ...

  6. Java多线程系列--“JUC锁”05之 非公平锁

    转载自:http://www.cnblogs.com/skywang12345/p/3496651.html点击打开链接 概要 前面两章分析了"公平锁的获取和释放机制",这一章开始 ...

  7. memcached 分布式锁 java_分布式锁的三种实现方式

    分布式锁的三种实现方式 一.zookeeper 1.实现原理: 基于zookeeper瞬时有序节点实现的分布式锁,其主要逻辑如下(该图来自于IBM网站).大致思想即为:每个客户端对某个功能加锁时,在z ...

  8. mysql行锁怎么读_MySQL锁(三)行锁:幻读是什么?如何解决幻读?

    概述 前面两篇文章介绍了MySQL的全局锁和表级锁,今天就介绍一下MySQL的行锁. MySQL的行锁是各个引擎内部实现的,不是所有的引擎支持行锁,例如MyISAM就不支持行锁. 不支持行锁就意味着在 ...

  9. Java实现分布式锁的三种方式

    文章目录 前言 一.基于数据库实现分布式锁 二.Redisson实现分布式锁 三.Zookeeper实现分布式锁 四.总结 前言 目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问 ...

最新文章

  1. 征战全球16年:中国手机出海简史
  2. 超级封装RecyclerView的适配器Adapter 只需二三十行代码
  3. C语言不使用结构体实现链表,不用指针链表和结构体数组怎么编学生成绩管理系统啊...
  4. 如何确定固定资产入账价值
  5. Springboot-data-jpa
  6. 张小龙:做 PC 版微信是一种破坏,本来不想做
  7. 大数据,并非一蹴而就
  8. java中面向对象_java中的面向对象
  9. 蓝桥杯 基础练习 芯片测试
  10. Neutron/ML2学习
  11. 【渝粤教育】国家开放大学2018年秋季 0690-22T化工原理及实验 参考试题
  12. 日本电子业转型的东芝之困:多年亏损 后有强敌追兵
  13. Android studio 导入 Android 系统源码
  14. mysql卸载不_mysql卸载不干净解决方法
  15. Google Maps基站定位
  16. 百变精灵、灵萌仙宠,《神都降魔》带您遨游仙界!
  17. 量化的股票交易策略是什么意思?
  18. 管家婆服装.NET II TOP 系列,安装过程中提示“silverlight/Sys未定义”错误,解决方案
  19. C语言中求字符串长度的函数my_strlen()的几种实现方法
  20. Bobby Axelrod要回归Billions???

热门文章

  1. windows怎么查看进程的启动时间
  2. 内网突破SSL嗅探的探究
  3. frida 安装特定版本
  4. 闻茂泉:系统性能监控与分析的工程化实践之路
  5. 跟Kafka学技术-缓冲池的使用
  6. RabbitMQ管理(1)——多租户与权限
  7. 【日程发布】LiveVideoStackCon 音视频技术大会 2022 上海站
  8. 声网纳斯达克上市、TikTok推出TikTok For Business、亚马逊推出无代码应用| Decode the Week...
  9. LiveVideoStack线上分享第五季(十三):高性能视频硬件编码
  10. LiveVideoStackCon2019北京参会手册