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 ...
随机推荐
- JSR 303 - Bean Validation 介绍及最佳实践
JSR 303 - Bean Validation 介绍及最佳实践 JSR 303 – Bean Validation 是一个数据验证的规范,2009 年 11 月确定最终方案.2009 年 12 月 ...
- 必须使用“角色管理工具”安装或配置Microsoft .NET Framework 3.5 SP1
在Windows Server 2008下直接安装SQL Server 2008时,会出现如下错误: 必须使用“角色管理工具”安装或配置Microsoft .NET Framework 3.5 SP1 ...
- centos7下安装vsftpd与PAM虚拟用户
Vsftp与PAM虚拟用户 使用yum 安装vsftp yum install vsftpd pam pam-* db4 db4-* 设置开机启动 chkconfig vsftpd on 创建一个保存 ...
- .netGDI+(转)
架上图片了你就可以在画板上涂改了啊我要写多几个字上去 string str = "Baidu"; //写什么字? Font font = Font("宋体",3 ...
- SQL 之witn as语法
with as 是临时视图的语法:with qry_a as (select * from table_a )select * from qry_a ;
- Tomcat中解决sql server连接失败--- java.lang.ClassNotFoundException: com.microsoft.jdbc.sqlserver.SQLServerDriver
php连接mysql数据库很容易,他俩真是黄金搭档.最近转战java连接微软sqlServer,步骤稍微复杂一点,但也不是太难,中途遇到了一点小问题,最后在csdn论坛里找到了答案http://bbs ...
- web_reg_find()函数的使用
1.此函数的作用,很显然就是能告之测试人员页面是否显示正确,其意义与价值在我此次支撑平台的性能测试得到了体现. 2.在使用此函数的过程中,遇到了非常郁闷的事情,幸得老大的帮助才得以跳出误区.当在此函数 ...
- vbs脚本要求在cmd中输入输出用StdIn ,StdOut
Dim StdIn, StdOutSet StdIn = WScript.StdInSet StdOut = WScript.StdOut Do While Not StdIn.AtEndOfStre ...
- 使用虚幻引擎中的C++导论(二-UE4基类)
使用虚幻引擎中的C++导论(二) 第一,这篇是我翻译的虚幻4官网的新手编程教程,原文传送门,有的翻译不太好,但大体意思差不多,请支持我O(∩_∩)O谢谢. 第二,某些细节操作,这篇文章省略了,如果有不 ...
- 碎片事物的提交 commitAllowingStateLoss()
转:http://blog.csdn.net/kaiqiangzhang001/article/details/42241441 下边两个问题,是在开发中碰到的一些关于Fragment的偶发性的问题, ...