`
747017186
  • 浏览: 331357 次
社区版块
存档分类
最新评论

condition线程之间的通信2

 
阅读更多

如果实现3个线程之间的协调通信,我们该怎么做?

1、先看传统的解决方案:

package thread.condition201801;

public class Test201801 {
	public static void main(String[] args) throws Exception{
		final ThreadTask threadTask = new ThreadTask();//业务任务对象
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<50;i++){
					threadTask.loopTask2();//子线程2任务
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<50;i++){
					threadTask.loopTask3();//子线程3任务
				}
			}
		}).start();
		
		
		for(int i=0;i<50;i++){
			threadTask.mainTask1();//主线程1任务
		}
	}
}

/**
*里面方法必须都是同步的
*/
class ThreadTask{
	private int flag = 1;//主线程、子线程运行标志
	
	public synchronized void mainTask1() {
		while(flag != 1){
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for(int i=1;i<=50;i++) {
			System.out.println("主线程1执行:"+i);
		}
		flag = 2;
		this.notifyAll();//对于两个以上的线程需要全部唤醒,争抢CPU的资源
//		this.notify();//对于两个线程可以使用,三个以上不要使用会引发死锁
	}
	
	public synchronized void loopTask2() {
		while(flag != 2){//防止线程虚假唤醒
			try {
				this.wait();//线程等待
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for(int i=1;i<=100;i++) {
			System.out.println("子线程2执行:"+i);
		}
		flag = 3;
		this.notifyAll();//唤醒线程
	}
	
	public synchronized void loopTask3() {
		while(flag != 3){//防止线程虚假唤醒
			try {
				this.wait();//线程等待
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for(int i=1;i<=100;i++) {
			System.out.println("子线程3执行:"+i);
		}
		flag = 1;
		this.notifyAll();//唤醒线程
	}
}

可以看到三个线程不能再使用notify方法了,因为这个方法是随机唤醒一个等待的线程,如果唤醒的那个线程刚刚wait,那么在此唤醒条件不满足依旧wait,这样容易导致死锁,所以必须使用notifyAll方法,一定要注意的是wait和notify、notifyAll都必须在synchronized下使用。 

2、看看一个condition是怎么实现的:

package thread.condition201802;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test201802 {
	public static void main(String[] args) throws Exception{
		final ThreadTask threadTask = new ThreadTask();//业务任务对象
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<50;i++){
					threadTask.loopTask2();//子线程2任务
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<50;i++){
					threadTask.loopTask3();//子线程3任务
				}
			}
		}).start();
		
		
		for(int i=0;i<50;i++){
			threadTask.mainTask1();//主线程1任务
		}
	}
}

class ThreadTask{
	Lock lock = new ReentrantLock();
	Condition condition1 = lock.newCondition();
	
	private int flag = 1;//主线程、子线程运行标志
	public void mainTask1() {
		lock.lock();
		try {
			while(flag != 1){
				try {
					condition1.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for(int i=1;i<=50;i++) {
				System.out.println("主线程1执行:"+i);
			}
			flag = 2;
			condition1.signalAll();//对于两个以上的线程需要全部唤醒,争抢CPU的资源
//			condition1.signal();//对于两个线程可以使用,三个以上不要使用会引发死锁
		} finally {
			lock.unlock();
		}
	}
	
	public void loopTask2() {
		lock.lock();
		try {
			while(flag != 2){//防止线程虚假唤醒
				try {
					condition1.await();//线程等待
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for(int i=1;i<=100;i++) {
				System.out.println("子线程2执行:"+i);
			}
			flag = 3;
			condition1.signalAll();//唤醒线程
		} finally {
			lock.unlock();
		}
		
	}
	
	public void loopTask3() {
		lock.lock();
		try {
			while(flag != 3){//防止线程虚假唤醒
				try {
					condition1.await();//线程等待
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for(int i=1;i<=100;i++) {
				System.out.println("子线程3执行:"+i);
			}
			flag = 1;
			condition1.signalAll();//唤醒线程
		} finally {
			lock.unlock();
		}
	}
}

 一个condition也是可以实现的,原理跟传统的差不多。这里不再做解释。

3、三个condition来实现三个线程之间的通信

package thread.condition201803;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test201803 {
	public static void main(String[] args) throws Exception{
		final ThreadTask threadTask = new ThreadTask();//业务任务对象
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<50;i++){
					threadTask.loopTask2();//子线程2任务
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<50;i++){
					threadTask.loopTask3();//子线程3任务
				}
			}
		}).start();
		
		
		for(int i=0;i<50;i++){
			threadTask.mainTask1();//主线程1任务
		}
	}
}

class ThreadTask{
	Lock lock = new ReentrantLock();
	Condition condition1 = lock.newCondition();
	Condition condition2 = lock.newCondition();
	Condition condition3 = lock.newCondition();
	
	private int flag = 1;//主线程、子线程运行标志
	public void mainTask1() {
		lock.lock();
		try {
			while(flag != 1){
				try {
					condition1.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for(int i=1;i<=50;i++) {
				System.out.println("主线程1执行:"+i);
			}
			flag = 2;
			condition2.signal();//唤醒线程
		} finally {
			lock.unlock();
		}
	}
	
	public void loopTask2() {
		lock.lock();
		try {
			while(flag != 2){//防止线程虚假唤醒
				try {
					condition2.await();//线程等待
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for(int i=1;i<=100;i++) {
				System.out.println("子线程2执行:"+i);
			}
			flag = 3;
			condition3.signal();//唤醒线程
		} finally {
			lock.unlock();
		}
		
	}
	
	public void loopTask3() {
		lock.lock();
		try {
			while(flag != 3){//防止线程虚假唤醒
				try {
					condition3.await();//线程等待
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for(int i=1;i<=100;i++) {
				System.out.println("子线程3执行:"+i);
			}
			flag = 1;
			condition1.signal();//唤醒线程
		} finally {
			lock.unlock();
		}
	}
}

 三个condition按照业务逻辑去唤醒特定的线程,这个方法至特定唤醒某一个线程,不需要随机去唤醒或者全部唤醒,更加有针对性

比如:

notifyAll、signalAll:唤醒全部线程,本来都在睡觉都叫醒任何自己去争夺CPU,发现不该自己做事(条件不满足)继续去wait。

object.notify():随机唤醒一个线程,该线程可能是需要唤醒的线程,也可能不是需要唤醒的线程。如果是需要唤醒的线程则继续工作,唤醒不该唤醒的线程则唤醒线程继续wait,导致死锁(三个或者三个以上的线程会出现,两个则不会)。

condition.signal():指定某个线程进行唤醒,可以给每个线程都定义一个condition来控制每个线程的行为习惯,非常方便。但是对于多个线程也可以用一个condition来进行控制,但是其用法就和notify方法一样了。

 

实现的效果就是主线程1---》子线程2-----》子线程3-----》主线程1  交替往复50次。

 

 

 

  • 大小: 13.9 KB
  • 大小: 13.5 KB
  • 大小: 14.1 KB
分享到:
评论

相关推荐

    多线程之间的线程通信

    "多线程之间的线程通信"是确保多个线程协同工作、避免数据不一致性和提高程序效率的关键概念。在本话题中,我们将深入探讨线程通信的原理、方法,以及潜在的危险。 首先,线程通信是指在一个进程中,不同的线程之间...

    线程的几种控制方式以及线程间的几种通信方式

    4. **线程间通信**:线程间通信允许线程之间交换信息,Java提供了多种机制,如`wait()`, `notify()`, `notifyAll()`,Python中则有`Condition`对象。 5. **线程休眠**:Java的`Thread.sleep()`方法可以让线程暂停...

    线程间通信的定义及全局变量的方法

    首先,线程间通信指的是在同一个进程中的多个线程之间交换信息或数据的过程。由于线程共享同一个进程的内存空间,线程间的通信相对来说比较容易实现。最简单的通信方式就是使用全局变量。全局变量对于进程内的所有...

    操作系统中多线程之间通信

    首先,多线程通信(Inter-Thread Communication, ITC)是多线程编程中的关键部分,它涉及到线程间的同步和异步操作。同步是为了确保线程按照预定的顺序执行,防止数据竞争和死锁等问题;异步则允许线程独立执行,...

    创建线程及线程间通信

    线程通信是线程协作完成任务的关键,它允许线程之间交换数据或同步操作。一种常见的通信机制是“生产者-消费者”模型,其中生产者线程生成数据,而消费者线程消费这些数据。在没有适当的同步机制下,可能会出现数据...

    进程线程通信,线程同步,异步,进程通信经典进程间通信.7z

    在计算机科学中,进程线程通信、线程同步与异步以及进程间的通信是操作系统核心概念,对于理解和优化多任务并行处理至关重要。这些概念在软件开发,尤其是并发编程领域中占据着举足轻重的地位。 首先,让我们来探讨...

    Java的多线程-线程间的通信.doc

    线程的状态转换是理解线程通信的基础,主要包括四个状态:新(New)、可执行(Runnable)、死亡(Dead)和停滞(Blocked)。新状态是指线程对象已创建但未启动;可执行状态意味着线程可能在等待CPU资源或正在执行;...

    线程间通信求和逆序源代码

    当一个程序包含多个并发执行的线程时,线程间通信用于协调它们之间的活动,确保数据的一致性和正确性。在这个场景中,"线程间通信求和逆序源代码"显然涉及到在多线程环境中实现数字序列的求和以及结果的逆序输出。 ...

    VC中利用多线程技术实现线程之间的通信

    2. **事件对象**:VC++中的事件对象(` HANDLE`类型)可用于线程间的同步。线程可以通过`WaitForSingleObject`或`WaitForMultipleObjects`函数等待事件对象的状态改变,从而触发线程间的通信。 3. **信号量**:信号...

    使用全局对象进行线程间的通信

    线程通信是指不同的线程间交换信息或同步执行的过程,这对于实现并发操作和协调不同任务至关重要。本篇文章将深入探讨如何在VC++ 2008中利用全局变量进行线程间的通信。 首先,我们需要了解全局变量的作用。全局...

    多线程编程之三——线程间通讯

    线程间通信是多线程编程中的核心概念,它允许不同线程之间交换信息和协调工作。当一个程序中存在多个并发执行的线程时,它们可能需要共享数据或者互相通知事件的发生,这就需要线程间通信机制。下面将详细讨论几种...

    多线程技术实现线程之间的通信

    在线程通信中,同步是非常关键的一环,防止数据竞争和死锁的发生。死锁是指两个或多个线程互相等待对方释放资源,导致无法继续执行的情况。为了避免死锁,应遵循一定的设计原则,如避免循环等待,合理分配资源,使用...

    线程通信(Condition) 实例

    线程通信(Condition)实例,完整的代码文件,你只需要编译运行即可,就可以看看结果,然后分析。

    Java使用Condition控制线程通信的方法实例详解

    使用 Condition 控制线程通信的方法可以提高线程间的协调和通信,提高程序的效率和可靠性。 Condition 的优点: * Condition 可以实现更高级的线程同步机制。 * Condition 可以在多个线程之间实现更好的协调和...

    传智播客_张孝祥_传统线程同步通信技术

    张孝祥老师的课程"传智播客_张孝祥_传统线程同步通信技术"深入浅出地讲解了这一主题,旨在帮助开发者理解和掌握线程间的协作与数据共享方式。 线程同步是指在多线程环境下,控制多个线程按一定的顺序执行,以避免...

    多线程网络通信演示

    线程的创建、同步和管理是多线程编程的关键部分,需要合理地设计线程间的数据交互和同步机制,如互斥锁(mutexes)、条件变量(condition variables)或信号量(semaphores),以避免竞态条件和死锁。 在提供的...

    Java 线程通信示例 源代码

    这个"Java线程通信示例源代码"很可能包含了演示如何在不同线程之间共享数据和协调执行顺序的实例。线程通信主要涉及两个核心概念:同步和互斥。 1. **线程同步**:线程同步是为了防止多个线程同时访问共享资源,...

    java并发之线程间通信协作.docx

    Java提供了多种线程间通信的机制,其中最常见的两种方式是基于`synchronized`关键字的`Object`类的`wait()`、`notify()`和`notifyAll()`方法,以及使用`ReentrantLock`类的`Condition`接口的`await()`、`signal()`和...

    Java多线程-线程间的通信

    为了确保数据的一致性和程序的正确执行,线程之间需要有一种有效的通信机制。 **举例说明**: 假设有一个简单的生产者-消费者模型。其中,线程A(生产者)负责生产包子,线程B(消费者)负责消费包子。为了避免...

Global site tag (gtag.js) - Google Analytics