一.需求

实现线程间的通信,主线程循环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. CSS3 旋转代码备忘

    .Aclose { -webkit-transition-property: all; -webkit-transition-duration: .3s; -moz-transition-proper ...

  2. 使用dojoConfig配置dojo(翻译)

    http://dojotoolkit.org/documentation/tutorials/1.10/dojo_config/index.html dojoConfig对象(原来是djConfig对 ...

  3. Asp.net中WebForm 与 MVC的架构区别

    ASP.NET Webform 后台代码(behind code) 这种behind code 模式有5个问题,我们用MVC的设计思想来分别解决这些问题 1.基于视图的方案来解决基于行为的需求 从上图 ...

  4. gerrit error: unpack failed: error Permission denied

    gerrit服务器迁移后,clone和pull代码到本地,都没问题. 但是,push时,报错: 查看了下git版本库存储目录,发现git下版本库镜像文件owner都是root.因为之前安装的gerri ...

  5. 黄聪:C#操作Word表格的常见操作(转)

    几种常见C#操作Word表格操作有哪些呢?让我们来看看具体的实例演示: bool saveChange = false; //C#操作Word表格操作 object missing = System. ...

  6. JAVA 新手问题: Request 编码编译出错,Unhandled exception type UnsupportedEncodingException

    新手: 编写如下代码 private void Exec(HttpServletRequest Req,HttpServletResponse Response) //throws ServletEx ...

  7. 修复山寨版的J-Link

    Fixed J-Link 1. Erase   (1) Power On   (2) Jump "ERASE"(JP3)   (3) Wait for 5s   (4) Break ...

  8. invalid END header (bad central directory offset) 异常解决方法

    今天版本升级时,一个ear包在传到aix下,weblogic后启动出现 invalid END header (bad central directory offset) 后来才发下是文件传输中出现了 ...

  9. 如何利用tomcat和cas实现单点登录(1):配置tomcat的ssl和部署cas

    如何利用tomcat和cas实现单点登录,借鉴了网上的很多教程,主要分为以下几个步骤: 一:下载好cas,tomcat之后,首先配置tomcat: 用鼠标右键点击"计算机"→选择& ...

  10. Flex加载google地图、百度地图以及天地图作底图

    一  Flex加载Google地图作底图 (1)帮助类GoogleLayer.as /* * 根据输入的地图类型加载Google地图(by chenyuming) */ package Layers ...