一.需求

实现线程间的通信,主线程循环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. powerdsigner Association Multiplicity

    这一篇來告诉一个不容易分辨的关系图式:Association(结合)的各种類型,除了了解它的涵义 外,也让各位可以看图說故事,知道它背后所要表达的意义. Association结合 Associati ...

  2. SQL Server 2008 收缩日志 清空删除大日志文件 转载

    SQL Server 2008 收缩日志 清空删除大日志文件 由于SQL2008对文件和日志管理进行了优化,所以以下语句在SQL2005中可以运行但在SQL2008中已经被取消:(SQL2005)Ba ...

  3. Django常用命令及参数配置(Django 1.8.6)

    常用命令 #新建Django项目 django-admin startproject mysite(项目名) #新建一个APP cd mysite python manager.py startapp ...

  4. 创建MySQL 用户

    create user 'lixianming'@'localhost' identified by 'lxm123456'; grant all on art.* to 'lixianming'@' ...

  5. vi编辑器的简单使用

    Esc   --进入扩展模式 a i o    --进入插入模式 w --保存 q --退出 wq!--强制保存退出 p  --粘贴 前面加数字表示粘贴多少行 u --复原前一个操作 Carl+r - ...

  6. [家里蹲大学数学杂志]第432期Hardy type inequalities

    If $p>1$, $f\geq 0$, and $$\bex F(x)=\int_0^x f(t)\rd t, \eex$$ then $$\bee\label{Hardy:0 to x} \ ...

  7. CSS基本语法

    这里主要介绍Bootstrap里用到的CSS语法,以便在源码分析时更容易理解和学习.Bootstrap的CSS组件的核心就是选择器的定义以及在各自优先级上的处理. 优先级 如何确定CSS的优先级,这里 ...

  8. Android 日常开发总结的技术经验 60 条

    1. 全部Activity可继承自BaseActivity,便于统一风格与处理公共事件,构建对话框统一构建器的建立,万一需要整体变动,一处修改到处有效. 2. 数据库表段字段常量和SQL逻辑分离,更清 ...

  9. CCF NOI系列活动

    NOI-全国青少年信息学奥林匹克竞赛全国青少年信息学奥林匹克竞赛(NOI)是国内信息学领域内面向中学生的最高水平的大赛,每省派经选拔产生的选手(其中一名是女选手)参加,NOI每年在不同的省市举行. N ...

  10. Change the Windows 7 Taskbar Thumbnail and List Mode

    Manually in Registry Editor 1. Open the Start Menu, then type regedit in the search boxand press Ent ...