一.需求

实现线程间的通信,主线程循环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控制线程通信的更多相关文章

  1. Java核心知识点学习----多线程并发之线程间的通信,notify,wait

    1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...

  2. java核心知识点学习----多线程并发之线程同步

    1.什么是线程同步? 多线程编程是很有趣的事情,它很容易出现"错误情况",这种情况不是由编码造成的,它是由系统的线程调度造成的,当使用多个线程来访问同一个数据时,很容易出现&quo ...

  3. Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍

    1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过s ...

  4. Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统

    理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...

  5. Condition控制线程通信

    Condition控制线程通信 一.前言 java.util.concurrent.locks.Condition 接口描述了可能会与锁有关联的条件变量.这些变量在用法上与使用Object.wait ...

  6. Java核心知识点学习----线程中的Semaphore学习,公共厕所排队策略

    1.什么是Semaphore? A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acq ...

  7. Java核心知识点学习----线程同步工具类,CyclicBarrier学习

    线程同步工具类,CyclicBarrier日常开发较少涉及,这里只举一个例子,以做备注.N个人一块出去玩,相约去两个地方,CyclicBarrier的主要作用是等待所有人都汇合了,才往下一站出发. 1 ...

  8. Java核心知识点学习----多线程 倒计时记数器CountDownLatch和数据交换的Exchanger

    本文将要介绍的内容都是Java5中的新特性,一个是倒计时记数器---CountDownLatch,另一个是用于线程间数据交换的Exchanger. 一.CountDownLatch 1.什么是Coun ...

  9. java核心知识点学习----创建线程的第三种方式Callable和Future CompletionService

    前面已经指出通过实现Runnable时,Thread类的作用就是将run()方法包装成线程执行体,那么是否可以直接把任意方法都包装成线程执行体呢?Java目前不行,但其模仿者C#中是可以的. Call ...

随机推荐

  1. Servlet与JSP的区别

    一.基本概念 1.1 Servlet Servlet是一种服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面.它担当客户请求(Web浏览器或其他HTTP客户程序)与服务器 ...

  2. UML的类图、时序图表示方法以及惯例

    <UML类图图示样例>说明:http://wenku.baidu.com/link?url=DEaRFyVIAH4kZ7TolplfFhFhmAk3gFaNSOH7XPzfTnCWY4CB ...

  3. 禁用sqlserver的锁升级

    锁升级 SQLSERVER.DB2中的锁是内存里面实现的,这就有个资源消耗问题,当锁的数量达到一个阀值或内存有压力时,就会引发锁升级.实际的情况是从row lock直接升级到table lock,而不 ...

  4. 转:Elasticsearch TermQuery 详解

    JavaClient 查询ES QueryBuilder queryBuilder = QueryBuilders.termQuery("字段","term值" ...

  5. MSSQL 获取汉字全拼 和 汉字首字母

    --获取全拼 DECLARE @str VARCHAR(max) SET @str= [dbo].[fn_Getquanpin]('中山') PRINT(@str) )) ) as begin ),) ...

  6. StringIO学习

    StringIO StringIO的行为与file对象非常像,但它不是磁盘上文件,而是一个内存里的“文件”,我们可以将操作磁盘文件那样来操作StringIO.一个简单的例子,让你对StringIO有一 ...

  7. (gridcontrol等)通用导出excel z

    关于DevExpress Winform 的所有可打印控件的导出excel 的通用方法,并且解决DevExpress控件自带的方法存在的缺陷问题 1.解决GridControl自带方法不能导出图片: ...

  8. Hihocoder 1035 [树形dp]

    /* 题意: 不要低头,不要放弃,不要气馁,不要慌张. PS:人生第一道自己独立做出来的树形dp... 给一棵树,标号1到n,每条边有两个权值,步行时间和驾车时间.车在1号点. 给m个必须访问的关键点 ...

  9. Java正则表达式详解

    转自http://edu.yesky.com/edupxpt/18/2143018.shtml

  10. 【SSM 1】SpringMVC、Spring和Struts的区别

    导读:近期做到的项目中,用到的框架师SSM(SpringMVC+Spring+Mybatis),那么在这之前用过SSH,这里主要是区分一下SpringMVC和Struts,但是由于SpringMVC和 ...