当前位置: 首页 > 编程日记 > 正文

Condition

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

1、Condition的简介

线程通信中的互斥除了用synchronized、Object类的wait()和notify()/notifyAll()方式实现外,方法JDK1.5中提供的Condition配套Lock可以实现相同的功能。Condition中的await()和signal()/signalAll()就相当于Object的wait()和notify()/notifyAll()。传统线程的通信方式,Condition都可以实现。不过要注意的是,Condition是被绑定到Lock上的,所以要创建一个Lock的Condition必须使用newCondition()方法。在等待Condition时,允许发生“虚假唤醒”, 这通常作为对基础平台语义的让步。

Condition的强大之处在于它可以为多个线程间建立不同的Condition。

2、Condition源码中的例子

看JDK文档中的一个例子:假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存put 线程和take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个Condition实例来做到这一点。

——其实就是java.util.concurrent.ArrayBlockingQueue的功能。

class BoundedBuffer {  final Lock lock = new ReentrantLock();          //锁对象  final Condition notFull  = lock.newCondition(); //写线程锁  final Condition notEmpty = lock.newCondition(); //读线程锁  final Object[] items = new Object[100];//缓存队列  int putptr;  //写索引  int takeptr; //读索引  int count;   //队列中数据数目  //写  public void put(Object x) throws InterruptedException {  lock.lock(); //锁定  try {  // 如果队列满,则阻塞<写线程>  while (count == items.length) {  notFull.await();   }  // 写入队列,并更新写索引  items[putptr] = x;   if (++putptr == items.length) putptr = 0;   ++count;  // 唤醒<读线程>  notEmpty.signal();   } finally {   lock.unlock();//解除锁定   }   }  //读   public Object take() throws InterruptedException {   lock.lock(); //锁定   try {  // 如果队列空,则阻塞<读线程>  while (count == 0) {  notEmpty.await();  }  //读取队列,并更新读索引  Object x = items[takeptr];   if (++takeptr == items.length) takeptr = 0;  --count;  // 唤醒<写线程>  notFull.signal();   return x;   } finally {   lock.unlock();//解除锁定   }   }   

3、Condition demo

1)demo 1

接着上次(子线程和主线程依次轮流循环50的多线程面试题)的一道面试题,现在改用Condition和Lock来实现:

/*** 面试题目:子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着又回到主线程又循环100次,如此循环50次。写出程序* * 经验:要用到共同数据(包括同步锁)或共同算法的若干个方法应该归在同一个类身上,这种设计体现了高类聚和程序的健壮性。* * 采用condition通信方式:Condition的功能类似在传统线程技术中的Object.wait()和Object.notify的功能。* 在等待Condition时,允许发生“虚假唤醒”。*/
public class ConditionCommunication {public static void main(String[] args) {final Business business = new Business();// 子线程循环new Thread(new Runnable() {@Overridepublic void run() {for (int i = 1; i <= 50; i++) {try {business.sub(i);} catch (InterruptedException e) {}}}}).start();// 主线程循环for (int i = 1; i <= 50; i++) {try {business.mian(i);} catch (InterruptedException e) {}}}/*** 业务类型(包含各色的同步锁)*/static class Business {Lock lock = new ReentrantLock();Condition condition = lock.newCondition();// sub()方法是否该运行标识private boolean bShouldSub = true;/*** 循环100次打印的方法sub()* * @param i* @throws InterruptedException*/public void sub(int i) throws InterruptedException {lock.lock();try {while (!bShouldSub) { // 当 bShouldSub 为 false 时,则等待condition.await(); // 不能写成condition.wait();,这里的wait()是Object的方法}for (int j = 1; j <= 10; j++) {System.out.println("sub thread :   第" + i + "行, 第" + j + "列");}bShouldSub = false; // 执行for循环后,标志sub()方法不可再执行condition.signal(); // 发信号} finally {lock.unlock();}}/*** 循环100次打印的方法mian()* * @param i* @throws InterruptedException*/public void mian(int i) throws InterruptedException {lock.lock();try {while (bShouldSub) {condition.await(); // 不能写成condition.wait();,这里的wait()是Object的方法}for (int j = 1; j <= 100; j++) {System.out.println("main thread :   第" + i + "行, 第" + j + "列");}bShouldSub = true; // 执行for循环后,标志sub()方法可再执行了condition.signal(); // 发信号} finally {lock.unlock();}}}
}

2)demo 2

用上面的demo1题目改装为:线程1循环10次,接着线程2循环20次,接着线程3循环30次,又回到线程1循环10次,接着又回到线程2循环20次……,如此循环50次。

分析:这种实现顺序唤醒的,可以采用创建多个Condition来实现。

写出程序:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 面试题目:线程1循环10次,接着线程2循环20次,接着线程3循环30次,又回到线程1循环10次,接着又回到线程2循环20次……,如此循环50次。写出程序*/
public class ConditionCommunication2 {public static void main(String[] args) {final Business business = new Business();// 线程2循环sub2()new Thread(new Runnable() {@Overridepublic void run() {for (int i = 1; i <= 50; i++) {try {business.sub2(i);} catch (InterruptedException e) {}}}}).start();// 线程3循环sub3()new Thread(new Runnable() {@Overridepublic void run() {for (int i = 1; i <= 50; i++) {try {business.sub3(i);} catch (InterruptedException e) {}}}}).start();// (主线程)线程1循环sub1()for (int i = 1; i <= 50; i++) {try {business.sub1(i);} catch (InterruptedException e) {}}}/*** 业务类型(包含各色的同步锁)*/static class Business {Lock lock = new ReentrantLock();Condition condition1 = lock.newCondition();Condition condition2 = lock.newCondition();Condition condition3 = lock.newCondition();// sub()方法是否该运行标识private int shouldSub = 1;/*** 循环10次打印的方法sub1()* * @param i* @throws InterruptedException*/public void sub1(int i) throws InterruptedException {lock.lock();try {while (shouldSub != 1) {  // 当 shouldSub 不为 1 时,则等待condition1.await(); // 不能写成condition.wait();,这里的wait()是Object的方法}for (int j = 1; j <= 10; j++) {System.out.println("sub1 thread :   第" + i + "行, 第" + j + "列");}shouldSub = 2; // 执行for循环后,标志下一个可以循环的方法时sub2()condition2.signal(); // condition2发信号} finally {lock.unlock();}}/*** 循环20次打印的方法sub2()* * @param i* @throws InterruptedException*/public void sub2(int i) throws InterruptedException {lock.lock();try {while (shouldSub != 2) {  // 当 shouldSub 不为 2 时,则等待condition2.await(); // 不能写成condition.wait();,这里的wait()是Object的方法}for (int j = 1; j <= 20; j++) {System.out.println("sub2 thread :   第" + i + "行, 第" + j + "列");}shouldSub = 3; // 执行for循环后,标志下一个可以循环的方法时sub3()condition3.signal(); // condition3发信号} finally {lock.unlock();}}/*** 循环30次打印的方法sub3()* * @param i* @throws InterruptedException*/public void sub3(int i) throws InterruptedException {lock.lock();try {while (shouldSub != 3) {  // 当 shouldSub 不为 3时,则等待condition3.await(); // 不能写成condition.wait();,这里的wait()是Object的方法}for (int j = 1; j <= 30; j++) {System.out.println("sub3 thread :   第" + i + "行, 第" + j + "列");}shouldSub = 1; // 执行for循环后,标志下一个可以循环的方法时sub1()condition1.signal(); // condition1发信号} finally {lock.unlock();}}}
}

转载于:https://my.oschina.net/u/3696939/blog/1842222

相关文章:

使用who.is查域名DNS信息以及用sameip.org查其他网站

www.who.is网站可以查域名信息&#xff0c;非常好用&#xff1a;例如查 hack-test.com然后我们可以找找同个IP上的其他站点&#xff08;旁站&#xff1a;sameip.org&#xff09;参考&#xff1a; 黑客是怎么攻击一个网站的&#xff1f;

基于 OpenCV 的人脸追踪

作者 | 努比 来源 | 小白学视觉 在Raspberry上启动项目很简单&#xff0c;所以让我们开始吧。 01. 产品清单 Raspberry Pi 4 Model B — 4GB 适用于Raspberry Pi的Pan-Tilt HAT Pi Camera v2 8MP 微型SD卡 迷你HDMI电缆 Raspberry Pi摄像头电缆—尺寸&#xff1a;457mm x …

-bash: /bin/rm: Argument list too long的解决办法

-bash: /bin/rm: Argument list too long的解决办法 当目录下文件太多时&#xff0c;用rm删除文件会报错&#xff1a; -bash: /bin/rm: Argument list too long 提示文件数目太多。 解决的办法是使用如下命令&#xff1a; ls | xargs -n 10 rm -fr ls 输出所有的文件名(用…

React使用ES6语法重构组件代码

首次使用react&#xff0c;要注意react不同版本库&#xff0c;是ES5还是ES6的写法&#xff0c;如何做到统一。下面对于ES6语法重构组件的代码如下&#xff1a;&#xff08;1&#xff09;原始代码&#xff1a; <script type"text/babel">var destinationdocumen…

PHP哈希表碰撞攻击原理

哈希表碰撞攻击&#xff08;Hashtable collisions as DOS attack&#xff09;的话题不断被提起&#xff0c;各种语言纷纷中招。本文结合PHP内核源码&#xff0c;聊一聊这种攻击的原理及实现。 哈希表碰撞攻击的基本原理 哈希表是一种查找效率极高的数据结构&#xff0c;很多语言…

Java8(jdk1.8)中文档注释处理工具javadoc的环境参量配置及使用方法

Java8(jdk1.8)中文档注释处理工具javadoc的环境参量配置及使用方法Java语言提供了一种功能强大的注释形式&#xff1a;文档注释。如果编写Java源代码时添加了合适的文档注释&#xff0c;然后通过JDK提供的javadoc工具可以直接将源代码里的文档注释提取成一份系统的API文档。jav…

如何读取Excel表格中不同sheet表的同一位置单元格数据,并绘制条形图呢?

作者 | 黄伟呢来源 | 数据分析与统计学之美今天&#xff0c;有位朋友在群里面咨询了一个问题&#xff1a;如何读取Excel表格中"不同sheet表"的同一位置单元格数据&#xff0c;并绘制条形图呢&#xff1f;有人提议用vba&#xff0c;但是不得不说&#xff0c;没有学过v…

vue-router学习笔记

配置路由模式 const routernew VueRouter({routes }) hash模式(默认):通过url的hash来模拟一个完整的url&#xff0c;于是当url改变时&#xff0c;页面不会重新加载。history模式&#xff1a;通过history完成url跳转而不需要重新加载页面。注意&#xff1a;为了防止404错误&…

PHP防止注入攻击

注入攻击不多说了PHP addslashes() 函数--单撇号加斜线转义PHP String 函数定义和用法addslashes() 函数在指定的预定义字符前添加反斜杠。这些预定义字符是&#xff1a;单引号 ()双引号 (")反斜杠 (\)NULL语法addslashes(string)参数描述string必需。规定要检查的字符串。…

首届腾讯数字安全创新大赛在京启动,挖掘新锐力量推动产业创新

3月10日&#xff0c;首届腾讯数字安全创新大赛在京正式启动。本次大赛由腾讯安全和中国产业互联网发展联盟联合主办&#xff0c;腾讯安全、KEEN、元起资本、赛博英杰、数世咨询等多家企业联合发起&#xff0c;中国产业互联网发展联盟安全专委会承办。 大赛旨在寻找网络安全新力…

oracle数据库无监听程序

在电脑---服务---启动oracle tns 如果还是出现错误的话&#xff0c;找到Net Manager&#xff0c;将网络的ip监听删除&#xff0c;将本机的主机名配好&#xff0c;即可打开tns服务 转载于:https://www.cnblogs.com/jiangsheng3/p/5025201.html

个人开发者即时到账收款方案 BufPay.com

BufPay 个人即时到账支付平台前言 作为独立开发者&#xff0c;一般只有一个人独立奋战&#xff0c;做出了产品需要收款是非常麻烦的&#xff0c;接入支付宝微信支付都需要公司公户&#xff0c;而注册公司、开公户等一系列操作非常麻烦&#xff0c;成本也很高一年也要 1w 左右。…

用 Python 制作数据大屏,超简单

作者 | 俊欣来源 | 关于数据分析与可视化今天我们用Streamlit模块来制作一个数据面板&#xff0c;将数据更加直观地呈现给别人观看&#xff0c;整个页面大致如下图所示&#xff1a;制作工具栏在页面的左侧是一个工具栏&#xff0c;工具栏中有多个按钮&#xff0c;分别是“About…

Oracle 12C -- 清空audit记录

1.使用job清空 SQL> dbms_audit_mgmt.create_purge_job(audit_trail_type> DBMS_AUDIT_MGMT.AUDIT_TRAIL_UNIFIED,audit_trail_purge_interval>12&#xff0c;audit_trail_purge_name>audit_trail_pj,use_last_arch_timestamp>TRUE,container>dbms_audit_mgm…

魔法引用函数magic_quotes_gpc和magic_quotes_runtime的区别和用法

PHP提供两个方便我们引用数据的魔法引用函数magic_quotes_gpc和magic_quotes_runtime&#xff0c; 这两个函数如果在php.ini设置为ON的时候&#xff0c;就会为我们引用的数据碰到单引号和双引号"是自动加上反斜线&#xff0c;帮我们自动转译符号&#xff0c;确保数据操作的…

Unity脚本生成插件:Script Create Dialog

最近写代码又犯懒了...感觉每次新建脚本都要写一堆简单重复的东西好无聊&#xff0c;所以搜索了一下有没有自动生成脚本的插件。结果还真被我发现了&#xff0c;官方在N久之前就制作了自动生成脚本的插件[Script Create Dialog]&#xff0c;大概是名字起的和脚本生成器相差太多…

多路IO复用模型 select epoll 等

同步阻塞IO在等待数据就绪上花去太多时间&#xff0c;而传统的同步非阻塞IO虽然不会阻塞进程&#xff0c;但是结合轮询来判断数据是否就绪仍然会耗费大量的CPU时间。多路IO复用提供了对大量文件描述符进行就绪检查的高性能方案。selectselect诞生于4.2BSD&#xff0c;在几乎所有…

可操作性强!Python实现一个电影订票系统!

来源丨Python小二一、效果展示通过Python实现一个电影订票系统&#xff0c;效果如下所示&#xff1a;二、整体结构图三、代码分解3.1 infos.py一部电影的详细信息适合用 字典 结构来存储&#xff0c;我们可以给字典里添加多个键值对来保存电影的名称、座位表和宣传时用的字符画…

centos7 install mysql

1. 下载mysql的repo源 $ wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 2. 安装mysql-community-release-el7-5.noarch.rpm包 $ sudo rpm -ivh mysql-community-release-el7-5.noarch.rpm 安装这个包后&#xff0c;会获得两个mysql的yum repo源&#x…

unity加载ab后,场景shader不起效问题(物件表现黑色)

需要把unity自带的shader&#xff0c;加入到默认列表转载于:https://www.cnblogs.com/lancidie/p/9293827.html

Linux下各类TCP网络服务器的实现源代码

http://www.linuxeden.com/forum/t146870.html大家都知道各类网络服务器程序的编写步骤&#xff0c;并且都知道网络服务器就两大类&#xff1a;循环服务和并发服务。这里附上源代码来个小结吧。首先&#xff0c;循环网络服务器编程实现的步骤是这样的&#xff1a; 这种服务器模…

ReferenceQueue的使用

转&#xff1a;http://www.iflym.com/index.php/java-programe/201407140001.html 1 何为ReferenceQueue 在java的引用体系中&#xff0c;存在着强引用&#xff0c;软引用&#xff0c;虚引用&#xff0c;幽灵引用&#xff0c;这4种引用类型。在正常的使用过程中&#xff0c;我们…

红帽、Docker、SUSE 在俄罗斯停服

‍‍国际局势给技术圈带来的影响依然在蔓延。整理 | 苏宓出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;继 Oracle、Google、苹果等科技公司和 React 开源项目之后&#xff0c;如今 Linux 发行版也牵扯进俄乌之间冲突的漩涡中。其中一个是全球最大的独立开源软件公…

配置linux-Fedora系统下iptables防火墙

参考地址&#xff1a;https://blog.csdn.net/zhangjingyi111/article/details/78902820 本篇文章为实验课过程记录&#xff0c;较为简略。 1.查看系统是否安装iptables 命令&#xff1a;iptables --version 2.开启iptables 命令&#xff1a;service iptables start 出现错误&am…

output_buffering详细介绍

HTTP Header为什么要使用Output Buffering技术Output Buffering的工作原理基本用法高级用法使事情更为简单哈哈&#xff0c;我成功了我个人认为&#xff0c;Output buffering是比较纯粹的PHP4.0特征。尽管从概念上看来相当简单&#xff0c;但是output buffering功能非常强大&am…

12 个 Pandas 数据处理高频操作

作者 | 老表来源 | 简说Python今天给大家分享几个自己近期常用的Pandas数据处理技巧&#xff0c;主打实用&#xff0c;所以你肯定能用的着&#xff0c;建议扫一遍&#xff0c;然后收藏起来&#xff0c;下次要用的时候再查查看即可。简单说说总结分享统计一行/一列数据的负数出现…

ORACLE初次安装自动安装软件包

一、自动安装所需软件包提前配置好yum仓库定义package.txt包列表文件&#xff1a;以官网RHEL6为例&#xff0c;这里有compat-libstdc有两个包&#xff0c;如果不加*&#xff0c;号后面的compat-libstdc-33-3.2.3-69.el6.x86_64&#xff0c;compat-libstdc-296-2.96-144.el6.i68…

中文详解phpmailer所有对象和属性

2019独角兽企业重金招聘Python工程师标准>>> 2009-03-09 19:13:50 前言&#xff1a; phpmailer是一个优秀的发件程序&#xff0c;但中文资料比较少&#xff0c;于是有牛人手动翻译了phpmailer的elementindex.html,E文的&#xff1a;[url]http://www.bblog.com/api…

php error_reporting 详解

error_reporting设定错误讯息回报的等级。语法: int error_reporting(int [level]);传回值: 整数函式种类: PHP 系统功能内容说明 本函式用来设定错误讯息回报的等级&#xff0c;参数 level 是一个整数的位元遮罩 (bitmask)&#xff0c;见下表。value constant 1 E_ERROR 2 E_W…

mysql多个实例

2019独角兽企业重金招聘Python工程师标准>>> 1>、关闭原有的默认端口3306的mysql:service mysqd stop 2>、拷贝或创建数据文件 cp -r /data/mysql/data1 /data/mysql/data_3307 格式 用bin/mysql_install_db --basedirmysql的目录 --datadir数据存放的目录 …