Java核心知识点学习----使用Condition控制线程通信
一.需求
实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次.
即:A->B->C---A->B->C---A->B->C
二.实现
1.分析
在前面文章java核心知识点学习----多线程并发之线程间的通信,notify,wait,曾实现过需求两个线程间隔循环的例子.涉及到3个线程就使用之间的方法就有点麻烦了,这里借着刚学的Lock锁可以很方便实现互斥,但如何实现三个线程间的通信呢?
2.实现效果

3.实现代码
package com.amos.concurrent; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @ClassName: ThreadSynchronizedConnect
* @Description:实现线程间的通信,需求:主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次.A->B->C---A->B->C---A->B->C
* @author: amosli
* @email:hi_amos@outlook.com
* @date Apr 20, 2014 4:39:44 PM
*/
public class ThreeConnect { public static void main(String[] args) {
final Business business = new Business();
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 3; i++) {
business.sub2(i);
}
}
}).start(); new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 3; i++) {
business.sub3(i);
}
}
}).start(); for (int i = 0; i < 3; i++) {
business.main(i);
}
} static class Business {
Lock lock = new ReentrantLock();
Condition conditionmain = lock.newCondition();
Condition conditionsub2 = lock.newCondition();
Condition conditionsub3 = lock.newCondition(); private int current = 1; // 子方法2
public void sub2(int i) {
lock.lock();
try {
if (current != 2) {// 如果不为true,将等待,Blocked状态
try {
conditionsub2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 0; j < 2; j++) {
System.out.println("sub2 thread:" + j + " loop:" + i);
}
current = 3;
conditionsub3.signal();// 唤醒3
} finally {
lock.unlock();
}
} // 子方法3
public void sub3(int i) {
lock.lock();
try {
if (current != 3) {// 如果不为true,将等待,Blocked状态
try {
conditionsub3.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int j = 0; j < 2; j++) {
System.out.println("sub3 thread:" + j + " loop:" + i);
}
current = 1;
conditionmain.signal();
} finally {
lock.unlock();
}
} // 主方法
public void main(int i) {
lock.lock();
try {
if (current != 1) {
try {
conditionmain.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int j = 0; j < 3; j++) {
System.out.println("main thread:" + j + " loop:" + i);
}
current = 2;
conditionsub2.signal();
} finally {
lock.unlock();
} } } }
4.代码说明
上面的代码中用的是Lock进行加锁操作的,然后线程间的通信没有用之前的wait(),notify()方法用的是Conditon的await()和signal()
为什么要使用Condition??
如果程序中不使用synchronized关键字来保证同步,而是使用Lock对象来保证数据同步,则系统中不存在隐式的同步监视器,也就不能使用wait().notify()方法进行线程通信了.
因为使用了Lock对象,所以要使线程间通信,可以使用Condition进行控制线程间通信.
Condition将同步监视器方法(wait(),notify(),notifyall()等)分解成截然不同的对象,以便通过将这些对象与Lock对象组合使用,为每个对象提供多个等待集(wait-set).
创建一个Condition,只需要lock.newCondition()即可,lock是已经new 好的ReentrantLock()对象.
>>await()方法与wait()功能类似,都是将线程加入到阻塞状态.
>>signal()方法与notify()方法类似,都是唤醒等待中的线程,只是signal()方法可以指定具体要唤醒的线程.
>>signalAll()方法与notifyAll()方法类似,都是唤醒所有等待中的线程.
5.扩展
1).下面是简单的对比,notify和signal等方法的对比,其效果是完全一样的.
package com.amos.concurrent; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @ClassName: ConditionConnect
* @Description:用condition替代wait,notify实现线程间的通信,需求:子线程循环10次,主线程循环100次,这样间隔循环50次.
* @author: amosli
* @email:hi_amos@outlook.com
* @date Apr 24, 2014 12:07:23 AM
*/
public class ConditionConnect { public static void main(String[] args) {
final Business business = new Business();
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 5; i++) {
business.sub(i);
}
}
}).start(); for (int i = 0; i < 5; i++) {
business.main(i);
}
} /*
* 经验:要用到共同数据(包括同步锁)的若干方法,应该归在同一个类身上,这样方便实现,高类聚和程序的健状性上.
*/
static class Business {
private boolean is_sub = true;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition(); // 子方法
public void sub(int i) {
lock.lock();
try {
while (!is_sub) {// 如果不为true,将等待,Blocked状态
try {
// this.wait();
condition.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int j = 0; j < 2; j++) {
System.out.println("sub thread:" + j + " loop:" + i);
}
is_sub = false;
// this.notify();//唤醒正在等待的线程
condition.signal();
} finally {
lock.unlock();
} } // 主方法
public void main(int i) {
lock.lock();
try {
while (is_sub) {
try {
// this.wait();
condition.await();
} catch (Exception e) {
e.printStackTrace();
}
} for (int j = 0; j < 10; j++) {
System.out.println("main thread:" + j + " loop:" + i);
}
is_sub = true;
// this.notify();
condition.signal();
} finally {
lock.unlock();
} }
} }
2).官方提供的例子
做了简单的修改:
先看效果:

再看代码:
package com.amos.concurrent; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @ClassName: ConditionTest
* @Description: 官方提供的例子
* @author: amosli
* @email:hi_amos@outlook.com
* @date Apr 24, 2014 12:40:58 AM
*/
public class ConditionTest {
public static void main(String[] args) throws Exception {
BoundedBuffer buffer = new BoundedBuffer();
buffer.put("hi_amos");
for(int i=0;i<3;i++){
buffer.put(i);
System.out.println("take:"+buffer.take());
} }
static 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;
++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();
}
}
}
}
思考:例子中为什么要new 2个condition??
Java核心知识点学习----使用Condition控制线程通信的更多相关文章
- Java核心知识点学习----多线程并发之线程间的通信,notify,wait
1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...
- java核心知识点学习----多线程并发之线程同步
1.什么是线程同步? 多线程编程是很有趣的事情,它很容易出现"错误情况",这种情况不是由编码造成的,它是由系统的线程调度造成的,当使用多个线程来访问同一个数据时,很容易出现&quo ...
- Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍
1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过s ...
- Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...
- Condition控制线程通信
Condition控制线程通信 一.前言 java.util.concurrent.locks.Condition 接口描述了可能会与锁有关联的条件变量.这些变量在用法上与使用Object.wait ...
- Java核心知识点学习----线程中的Semaphore学习,公共厕所排队策略
1.什么是Semaphore? A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acq ...
- Java核心知识点学习----线程同步工具类,CyclicBarrier学习
线程同步工具类,CyclicBarrier日常开发较少涉及,这里只举一个例子,以做备注.N个人一块出去玩,相约去两个地方,CyclicBarrier的主要作用是等待所有人都汇合了,才往下一站出发. 1 ...
- Java核心知识点学习----多线程 倒计时记数器CountDownLatch和数据交换的Exchanger
本文将要介绍的内容都是Java5中的新特性,一个是倒计时记数器---CountDownLatch,另一个是用于线程间数据交换的Exchanger. 一.CountDownLatch 1.什么是Coun ...
- java核心知识点学习----创建线程的第三种方式Callable和Future CompletionService
前面已经指出通过实现Runnable时,Thread类的作用就是将run()方法包装成线程执行体,那么是否可以直接把任意方法都包装成线程执行体呢?Java目前不行,但其模仿者C#中是可以的. Call ...
随机推荐
- Servlet与JSP的区别
一.基本概念 1.1 Servlet Servlet是一种服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面.它担当客户请求(Web浏览器或其他HTTP客户程序)与服务器 ...
- UML的类图、时序图表示方法以及惯例
<UML类图图示样例>说明:http://wenku.baidu.com/link?url=DEaRFyVIAH4kZ7TolplfFhFhmAk3gFaNSOH7XPzfTnCWY4CB ...
- 禁用sqlserver的锁升级
锁升级 SQLSERVER.DB2中的锁是内存里面实现的,这就有个资源消耗问题,当锁的数量达到一个阀值或内存有压力时,就会引发锁升级.实际的情况是从row lock直接升级到table lock,而不 ...
- 转:Elasticsearch TermQuery 详解
JavaClient 查询ES QueryBuilder queryBuilder = QueryBuilders.termQuery("字段","term值" ...
- MSSQL 获取汉字全拼 和 汉字首字母
--获取全拼 DECLARE @str VARCHAR(max) SET @str= [dbo].[fn_Getquanpin]('中山') PRINT(@str) )) ) as begin ),) ...
- StringIO学习
StringIO StringIO的行为与file对象非常像,但它不是磁盘上文件,而是一个内存里的“文件”,我们可以将操作磁盘文件那样来操作StringIO.一个简单的例子,让你对StringIO有一 ...
- (gridcontrol等)通用导出excel z
关于DevExpress Winform 的所有可打印控件的导出excel 的通用方法,并且解决DevExpress控件自带的方法存在的缺陷问题 1.解决GridControl自带方法不能导出图片: ...
- Hihocoder 1035 [树形dp]
/* 题意: 不要低头,不要放弃,不要气馁,不要慌张. PS:人生第一道自己独立做出来的树形dp... 给一棵树,标号1到n,每条边有两个权值,步行时间和驾车时间.车在1号点. 给m个必须访问的关键点 ...
- Java正则表达式详解
转自http://edu.yesky.com/edupxpt/18/2143018.shtml
- 【SSM 1】SpringMVC、Spring和Struts的区别
导读:近期做到的项目中,用到的框架师SSM(SpringMVC+Spring+Mybatis),那么在这之前用过SSH,这里主要是区分一下SpringMVC和Struts,但是由于SpringMVC和 ...