生产者消费者问题、防止虚假唤醒

生产者消费者问题、防止虚假唤醒

传统synchronized

package JUC;
/**   
 * Copyright © 2021 eSunny Info. Tech Ltd. All rights reserved.
 * 
 * 功能描述:生产者
 * 操作同一个变量 通知等待唤醒
 * Provider num + 1
 * Consumer num - 1
 */
public class ProviderConsumer {
    
    
	
	public static void main(String[] args) {
    
    
		Data data = new Data();
		new Thread(()->{
    
    
			for (int i = 0; i < 10; i++) {
    
    
				try {
    
    
					data.increment();
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
			}
		},"A") .start();
		
		new Thread(()->{
    
    
			for (int i = 0; i < 10; i++) {
    
    
				try {
    
    
					data.decrement();
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
			}
		},"B") .start();
	}
}

class Data{
    
    //数字 资源类
	
	private int number = 0;
	
	// +1
	public synchronized void increment() throws InterruptedException {
    
    
		if (number!=0) {
    
    
			//等待减少
			this.wait();
		}
		number++;
		System.out.println(Thread.currentThread().getName() + "票数加 +"+ number);
		
		//通知
		this.notifyAll();
	}
	
	// -1
	public synchronized void decrement() throws InterruptedException {
    
    
		if (number==0) {
    
    
			//等待增加
			this.wait();
		}
		number--;
		System.out.println(Thread.currentThread().getName() + "票数减 -"+ number);
		
		//通知
		this.notifyAll();
	}
	
}

在这里插入图片描述
2个线程看起来没有问题,但是当打开4个线程呢?

防止虚假唤醒

线程也可以唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒。虽然实践中很少发生,但应用程序必须通过测试应该使线程被唤醒的条件来防范,并且如果条件不满足则继续等待。换句话讲,等待应该总是出现在循环中:
将if 修改成while循环判断
在这里插入图片描述

lock锁 生产消费者

在这里插入图片描述

package JUC;

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

/**   
 * Copyright © 2021 eSunny Info. Tech Ltd. All rights reserved.
 * 
 * 功能描述:
 * @Package: JUC 
 * @author: 79283   
 * @date: 2021年1月20日 下午7:13:51 
 */
public class ProviderConsumerJUC {
    
    
	
	public static void main(String[] args) {
    
    
		DataJUC data = new DataJUC();
		new Thread(()->{
    
    
			for (int i = 0; i < 10; i++) {
    
    
				try {
    
    
					data.increment();
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
			}
		},"A") .start();
		
		new Thread(()->{
    
    
			for (int i = 0; i < 10; i++) {
    
    
				try {
    
    
					data.decrement();
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
			}
		},"B") .start();
		
		new Thread(()->{
    
    
			for (int i = 0; i < 10; i++) {
    
    
				try {
    
    
					data.increment();
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
			}
		},"C") .start();
		
		new Thread(()->{
    
    
			for (int i = 0; i < 10; i++) {
    
    
				try {
    
    
					data.decrement();
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
			}
		},"D") .start();
	}
}

class DataJUC{
    
    //数字 资源类
	
	private int number = 0;
	
	Lock lock = new ReentrantLock();
	//Condition 等待唤醒
	Condition newCondition = lock.newCondition();
	Condition newCondition2 = lock.newCondition();
	
	// +1
	public void increment() throws InterruptedException {
    
    
		lock.lock();
		try {
    
    
			while (number!=0) {
    
    
				//等待减少
				newCondition.await();
			}
			number++;
			System.out.println(Thread.currentThread().getName() + "票数加 +"+ number);
			
			//通知
			newCondition.signalAll();
		} catch (Exception e) {
    
    
			e.getStackTrace();
		} finally {
    
    
			lock.unlock();
		}
		
	}
	
	// -1
	public void decrement() throws InterruptedException {
    
    
		lock.lock();
		try {
    
    
			while (number==0) {
    
    
				//等待增加
				newCondition.await();
			}
			number--;
			System.out.println(Thread.currentThread().getName() + "票数减 -"+ number);
			
			//通知
			newCondition.signalAll();
		} catch (Exception e) {
    
    
			e.getStackTrace();
		} finally {
    
    
			lock.unlock();
		}
		
	}
	
}

猜你喜欢

转载自blog.csdn.net/jj89929665/article/details/112887264