Java多线程学习---Condition和wait、notify(十三)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/havebeenstand/article/details/83716427

1.问题:实现两个线程交叉执行(Condition和wait、notify都可以实现)

public class ConditionStudy {
	
	
	public static void main(String[] args) {
		//线程代码
		BussinessTest b = new BussinessTest();
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i = 1;i<=50;i++){
					b.subThreadCreate(i);
				}
			}
		}).start();
		
		for(int i = 1;i<=50;i++){
			b.mainThreadCreate(i);
		}
		
	}
	
}
//资源类
class BussinessTest{
	//指示是否该子线程执行的布尔临时变量
	private boolean isSub = true;
	
	private Lock lock = new ReentrantLock();
	
	private Condition condition = lock.newCondition();
	//子线程资源方法
	public  void subThreadCreate(int i){
		lock.lock();
		try{
			//如果不该子线程执行,子线程等待
			while(!isSub){
				try {
					condition.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for(int j = 1;j<=10;j++){
				System.out.println("sub thread number of "+j+" loop of "+i);
			}
			//子线程执行完,让指示是否该子线程执行为false
			isSub = false;
			//唤醒等待的主进程
			condition.signal();
		}finally{
			lock.unlock();
		}
	}
	//主线程资源方法
	public  void mainThreadCreate(int i){
		lock.lock();
		try{
			//如果该子进程去执行,让主进程等待
				while(isSub){
					try {
						condition.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				for(int j = 1;j<=100;j++){
					System.out.println("MAIN thread number of "+j+" loop of "+i);
				}
				//主进程执行完,轮到子进程去执行,令isSub为true
				isSub = true;
				//唤醒等待的子进程
				condition.signal();
		}finally{
			lock.unlock();
		}
	}
}

2.为什么有Object的wait方法和notify方法还需要Condition呢?

synchronized 方式对应的 wait, notify 不能有多个谓词条件,Lock 对应的 Condition await, signal 则可以有多个谓词条件

没有多个谓词条件带来的问题在于

例如队列已满,所有的生产者现场阻塞,某个时刻消费者消费了一个元素,则需要唤醒某个生产者线程,而通过 Object notify 方式唤醒的线程不能确保一定就是一个生产者线程,因为 notify 是随机唤醒某一个正在该 synchronized 对应的锁上面通过 wait 方式阻塞的线程,如果这时正好还有消费者线程也在阻塞中,则很可能唤醒的是一个消费者线程;signalAll 更是会唤醒所有在对应锁上通过 wait 方式阻塞的线程,而不管是生产者还是消费者线程。

与之不同的 Condition await, signal 方式则可以对应多个谓词条件(notEmpty, notFull),可以很方便的实现让生产者线程和消费者线程分别在不同的谓词条件上进行等待。所有的生产者线程在 notEmpty 谓词条件上等待,所有的消费者线程在 notFull 谓词条件上等待,当队列是满的时候所有的生产者线程阻塞,添加元素之后则唤醒某个消费者线程,此时则不用担心会唤醒消费者线程。

3.三个线程通信交叉执行---条件:线程一执行完,让线程二执行,线程二执行完让线程三执行,线程三执行完,再让线程一执行,一次次循环执行(只能用Condition来实现)

代码示例

public class ConditionStudy {
	
	
	public static void main(String[] args) {
		BussinessTest b = new BussinessTest();
		//线程1 执行5次
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i = 1;i<=5;i++){
					b.subThread1(i);
				}
			}
		}).start();
		//线程2 执行10次
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i = 1;i<=10;i++){
					b.subThread2(i);
				}
			}
		}).start();
		//线程3 执行15次
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i = 1;i<=15;i++){
					b.subThread3(i);
				}
			}
		}).start();
	}
	
}
//资源类
class BussinessTest{
	//指示该哪个线程执行
	private int shouldSub = 1;
	
	private Lock lock = new ReentrantLock();
	
	private Condition condition1 = lock.newCondition();
	private Condition condition2 = lock.newCondition();
	private Condition condition3 = lock.newCondition();
	//线程1执行方法
	public  void subThread1(int i){
		lock.lock();
		try{
			//如果不该1线程,让它等待
			while(shouldSub != 1){
				try {
					condition1.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for(int j = 1;j<=10;j++){
				System.out.println("sub thread1 number of "+j+" loop of "+i);
			}
			//1线程执行完了,让2去执行
			shouldSub  = 2;
			//唤醒等待的2线程
			condition2.signal();
		}finally{
			lock.unlock();
		}
	}
	//线程1执行方法
		public  void subThread2(int i){
			lock.lock();
			try{
				//如果不该2线程,让它等待
				while(shouldSub != 2){
					try {
						condition2.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				for(int j = 1;j<=10;j++){
					System.out.println("sub thread2 number of "+j+" loop of "+i);
				}
				//2线程执行完了,让3去执行
				shouldSub  = 3;
				//唤醒等待的3线程
				condition3.signal();
			}finally{
				lock.unlock();
			}
		}
		//线程1执行方法
		public  void subThread3(int i){
			lock.lock();
			try{
				//如果不该3线程,让它等待
				while(shouldSub != 3){
					try {
						condition3.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				for(int j = 1;j<=10;j++){
					System.out.println("sub thread3 number of "+j+" loop of "+i);
				}
				//3线程执行完了,让1去执行
				shouldSub  = 1;
				//唤醒等待的1线程
				condition1.signal();
			}finally{
				lock.unlock();
			}
		}

}

猜你喜欢

转载自blog.csdn.net/havebeenstand/article/details/83716427