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 ...
随机推荐
- [转].NET下读取PDF文本
本文转自:http://blog.csdn.net/wangqiuyun/article/details/8548779 在.NET下读取PDF文本用到的类库主要有两个:PDFBox和iTextSha ...
- 【Android UI设计与开发】1.引导界面(一)ViewPager介绍和简单实现
1.ViewPager 实现效果图 2.ViewPager 实现功能 ViewPager类提供了多界面切换的新效果,新效果有如下特征: <1>当前显示一组界面中的其中一个界面: <2 ...
- liunx中的进程与线程
1. 进程和线程 进程和线程是程序运行时状态,是动态变化的,进程和线程的管理操作(比如,创建,销毁等)都是有内核来实现的. Linux中的进程于Windows相比是很轻量级的,而且不严格区分进程和线程 ...
- mysql查询语句包含有关键字
查询mysql的时候,有时候mysql表名或者列名会有关键字.这时候查询会有错误.例如表名是order,查询时候会出错. 简单的办法是sql语句里表名或者列名加上`[tab键上面]来加以区别,例如se ...
- MongoDB学习(一)简介
本篇主要简单介绍一下MongoDB数据库. 一.简介 mongoDB是一个开源的,基于分布式的,面向文档存储的非关系型数据库.是非关系型数据库当中功能最丰富.最像关系数据库的. mongoDB由C++ ...
- js模拟手机触摸屏
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- iOS宏定义
1.__OBJC__宏定义作用 在.pch 文件中一般都会自动加上这句宏定义,表示宏内引用的文件确保只被使用Objective-C语言的文件所引用,保证引用关系的清晰.因为在一个OC工程中,可能包含. ...
- f2fs解析(十)nid 如何从nat_root中删除
上面我们谈到了一个nid如何从free_nid中转移到node_info中去[分别有一个链表和一棵基数树搭伙做事],讲free_nid时,详细说明了free_nid中是如何进如何出的,上一篇说了nid ...
- AutoMapper使用
1.安装 现在AutoMapper已经更新到5.0版本了,可查看 http://www.nuget.org/packages/AutoMapper/ 我环境是4.0的,nuget安装 http://w ...
- 了解了这些才能开始发挥jQuery的威力(转)
链接:http://www.cnblogs.com/dolphinX/archive/2013/10/08/3347677.html 由于当前jQuery如此的如雷贯耳,相信不用介绍什么是jQuery ...