java多线程-Condition
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
先看一个关于Condition使用的简单实例:
public class ConditionTest {
public static void main(String[] args) {
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
System.out.println("我需要等一个信号"+this);
condition.await();
System.out.println("我拿到一个信号"+this);
} catch (Exception e) {
// TODO: handle exception
} finally{
lock.unlock();
}
}
}, "thread1");
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
System.out.println("我拿到了锁");
Thread.sleep(500);
System.out.println("我发出一个信号");
condition.signal();
} catch (Exception e) {
// TODO: handle exception
} finally{
lock.unlock();
}
}
}, "thread2");
thread2.start();
}
}
运行结果:
我需要等一个信号com.luchao.traditionalthread.ConditionTest$1@10bc3c9
我拿到了锁
我发出一个信号
我拿到一个信号com.luchao.traditionalthread.ConditionTest$1@10bc3c9
可以看到,Condition的执行方式,是当在线程1中调用await方法后,线程1将释放锁,并且将自己沉睡,等待唤醒,线程2获取到锁后,开始做事,完毕后,调用Condition的signal方法,唤醒线程1,线程1恢复执行。
以上说明Condition是一个多线程间协调通信的工具类,使得某个,或者某些线程一起等待某个条件(Condition),只有当该条件具备( signal 或者 signalAll方法被带调用)时 ,这些等待线程才会被唤醒,从而重新争夺锁。
Condition与传统线程通信有些类似,它的使用更广,可以将多个线程进行通信,以完成更加复杂的通信。
用Condition替换传统线程通信,在前面的传统有一个子线程和主线程交替运行50次的实例,使用Condition也可以完成。
代码如下:
public class ConditionCommuniction {
public static void main(String[] args) {
final Business business = new Business();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
business.sub(i);
}
}
}).start();
for (int i = 0; i < 50; i++) {
business.main(i);
}
}
static class Business{
private Lock lock = new ReentrantLock();
private boolean isMain = true;
private Condition condition = lock.newCondition();
public void main(int i){
lock.lock();
try {
while(!isMain){
condition.await();
}
for (int j = 0; j < 100; j++) {
System.out.println("main is looping :" + j +" in " + i);
}
isMain = false;
condition.signal();
} catch (Exception e) {
// TODO: handle exception
} finally{
lock.unlock();
}
}
public void sub(int i){
lock.lock();
try {
while(isMain){
condition.await();
}
for (int j = 0; j < 10; j++) {
System.out.println("sub is looping :" + j +" in " + i);
}
isMain = true;
condition.signal();
} catch (Exception e) {
// TODO: handle exception
} finally{
lock.unlock();
}
}
}
}
在Condition中,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式,Condition都可以实现,这里注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。
这样看来,Condition和传统的线程通信没什么区别,Condition的强大之处在于它可以为多个线程间建立不同的Condition,下面引入API中的一段代码,加以说明。
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/*写索引*/, takeptr/*读索引*/, 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;//如果写索引写到队列的最后一个位置了,那么置为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;//如果读索引读到队列的最后一个位置了,那么置为0
--count;//个数--
notFull.signal();//唤醒写线程
return x;
} finally {
lock.unlock();
}
}
}
这就是多个Condition的强大之处,假设缓存队列中已经存满,那么阻塞的肯定是写线程,唤醒的肯定是读线程,相反,阻塞的肯定是读线程,唤醒的肯定是写线程,那么假设只有一个Condition会有什么效果呢,缓存队列中已经存满,这个Lock不知道唤醒的是读线程还是写线程了,如果唤醒的是读线程,皆大欢喜,如果唤醒的是写线程,那么线程刚被唤醒,又被阻塞了,这时又去唤醒,这样就浪费了很多时间。
将上面主线程和子线程交替运行的程序进行扩展,三个线程交替运行,代码如下:
public class ThreeConditionCommunication {
public static void main(String[] args) {
final Business business = new Business();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
business.sub1(i);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
business.sub2(i);
}
}
}).start();
for (int i = 0; i < 50; i++) {
business.main(i);
}
}
static class Business{
Lock lock = new ReentrantLock();
Condition main = lock.newCondition();
Condition sub1 = lock.newCondition();
Condition sub2 = lock.newCondition();
int runNum = 1;
public void main(int i){
lock.lock();
try {
while(runNum!=1){
main.await();//主线程等待
}
for (int j = 0; j < 100; j++) {
System.out.println("main is looping of "+j+" in "+i);
}
runNum = 2;
sub1.signal();//唤醒子线程1
} catch (Exception e) {
// TODO: handle exception
} finally{
lock.unlock();
}
}
public void sub1(int i){
lock.lock();
try {
while(runNum!=2){
sub1.await();//子线程1等待
}
for (int j = 0; j < 10; j++) {
System.out.println("sub1 is looping of "+j+" in "+i);
}
runNum = 3;
sub2.signal();//唤醒子线程2
} catch (Exception e) {
// TODO: handle exception
} finally{
lock.unlock();
}
}
public void sub2(int i){
lock.lock();
try {
while(runNum!=3){
sub2.await();//子线程2等待
}
for (int j = 0; j < 20; j++) {
System.out.println("sub2 is looping of "+j+" in "+i);
}
runNum = 1;
main.signal();//唤醒主线程
} catch (Exception e) {
// TODO: handle exception
} finally{
lock.unlock();
}
}
}
}
由此可见,Condition在多线程通信的强大作用,可以大大提高程序效率。
java多线程-Condition的更多相关文章
- Java多线程——Condition条件
简介 Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signa ...
- Java多线程Condition定点通知
多线程之间按顺序调用,实现A->B->C三个线程启动,要求如下:A打印5次,B打印10次,C打印15次接着 A打印5次,B打印10次,C打印15次 来10轮 package com.yan ...
- java多线程 -- Condition 控制线程通信
Api文档如此定义: Condition 将 Object 监视器方法(wait.notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对 ...
- Java多线程系列--“JUC锁”06之 Condition条件
概要 前面对JUC包中的锁的原理进行了介绍,本章会JUC中对与锁经常配合使用的Condition进行介绍,内容包括:Condition介绍Condition函数列表Condition示例转载请注明出处 ...
- Java多线程(九)之ReentrantLock与Condition
一.ReentrantLock 类 1.1 什么是reentrantlock java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 ...
- Java多线程系列--“JUC锁”03之 公平锁(一)
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
- Java多线程系列--“JUC锁”04之 公平锁(二)
概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...
- Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例
概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...
- Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock
本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...
随机推荐
- 使用Azure Automation(自动化)定时关闭和启动虚拟机
1. 概述 作为Windows Azure的用户,使用Azure的过程中,最担心的事情就是还没到月底,预设的费用就快消耗完了(下面两张账单图是我最讨厌看到的).但是仔细分析自己的费用列表,发现绝大部分 ...
- [知乎] 刚开始学习 iOS 开发有什么书推荐呢?
http://www.zhihu.com/question/19649679 我来说说我学习的过程:(无耻的使用一个回答 回答了很多问题.^^) 第一步,精读 Stephen G. Kochan 的& ...
- (转载)java多态(2)-------Java转型(向上或向下转型)
5.13.1 向上转型 我们在现实中常常这样说:这个人会唱歌.在这里,我们并不关心这个人是黑人还是白人,是成人还是小孩,也就是说我们更倾向于使用抽象概念“人”.再例如,麻雀是鸟类的一种(鸟类的子类), ...
- Jsp页显示时间标签JSTL标签 <fmt:formatDate/> 实例大全
<fmt:formatDate value="${isoDate}" type="both"/>2004-5-31 23:59:59 <fmt ...
- WebApi 返回小驼峰式 json 格式,并格式化日期
from:http://blog.csdn.net/magiccops/article/details/42969363 屏蔽默认返回xml格式:Global文件加:GlobalConfigurati ...
- scroll滚动条插件初始化问题
一种特殊场景下是滚动条容器先隐藏,点击某个东西后显示出来.然后实例化滚动条.实例 js: var flag = true; document.getElementById('btn1').onclic ...
- Gvim使用
VIM删除空白行 命令:g/^\s*$/d :g 代表在全文档范围内 ^代表行的开始 \s*代表空白字符 &代表行的结束 d代表删除 用//将3段代码隔开
- Mac 使用SSH远程登录
一.打开ssh Mac Terminal是自带SSH的,可以用whereis来看看: $ whereis ssh 但是在现有进程中找不到ssh对应的进程: $ ps aux | grep ssh ap ...
- Table AdvanceTable针对表内行禁用multipleSelection , singleSelection
OATableBean table = (OATableBean)webBean.findChildRecursive("LineTable"); table.setInserta ...
- 小程序基础02:全局配置app.json
1.配置 我们使用app.json文件来对来微信小程序进行全局配置. 作用:他决定了页面文件的路径,窗口表现,设置网络超时时间,设置多tab等 每一个小程序页面也可以使用 .json 文件来对本页面的 ...