线程通讯之生产者消费者(生产一个,消费一个)传统版和阻塞队列版

22 篇文章 0 订阅
10 篇文章 0 订阅
线程通讯之生产者消费者
  • 线程 操作(方法) 资源类
  • 判断 执行 通知
  • 防止虚假唤醒(await()的判断逻辑必须放到一个循环while里面,不能放在if里面)

实例:一个初始值为0的变量,两个线程对其进行交替操作,一个加1一个减1(生产一个,消费一个),来5轮

实现方式

传统版 1): Synchronized锁、await()等待、notify()唤醒
传统版 2): Lock锁(Condition的使用)、await()等待、signalAll()唤醒

传统版 2)的代码示例和解释:

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

/**
 * 线程通讯之生产者消费者模式 传统版 实例:一个初始值为0的变量,两个线程对其进行交替操作,一个加1一个减1(生产一个,消费一个),来5轮
 * 线程          操作(方法)  资源类
 * 判断          执行                    通知 
 * 防止虚假唤醒(await()的判断逻辑必须放到一个循环while里面,不能放在if里面)
 */
public class ProConsumer_TroditionDemo {

	public static void main(String[] args) {
		
		ShareData shareData = new ShareData();
		
		//线程AAA
		new Thread(()->{
			for(int i=1;i<=5;i++){
				//执行加1(生产操作)
				shareData.increment();
			}
		},"AAA").start();
		
		//线程BBB
        new Thread(()->{
        	for(int i=1;i<=5;i++){
        		//执行减1(消费操作)
        		shareData.decrement();
        	}
		},"BBB").start();
	}

}

// 资源类
class ShareData {
	
	private int number = 0;
	private Lock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();

	// 加1方法
	public void increment() {

		lock.lock();

		try {
			// 1)判断,number!=0为false,默认不会进入while循环
			while (number != 0) {
				// 等待,不能生产
				condition.await();// 新版写法,线程等待
			}
			// 2)干活
			number++;
			System.out.println(Thread.currentThread().getName() + "\t" + number);
			// 3)通知唤醒线程
			condition.signalAll();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}

	}

	// 减1方法
	public void decrement() {

		lock.lock();

		try {
			// 1)判断,number!=0为false,默认不会进入while循环
			while (number == 0) {
				// 等待,不能生产
				condition.await();// 新版写法,线程等待
			}
			// 2)干活
			number--;
			System.out.println(Thread.currentThread().getName() + "\t" + number);
			// 3)通知唤醒线程
			condition.signalAll();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}

	}

}

打印结果:
在这里插入图片描述
阻塞队列版的代码示例和解释:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程通讯之生产者消费者模式
 * 阻塞队列版(消息中间件基本上就是这个原理)
 * 
 */

//资源类
class MySource{
	
	//是否开启生产和消费的标志,true默认开启,volatile保证可见性
	private volatile boolean FLAG = true;
	//原子引用,保证原子性
	private AtomicInteger atomicInteger = new AtomicInteger();
	
	//通顺、适配和通用,传接口不传具体类
	//注入方式两种:set/get设值注入,构造注入
	BlockingQueue<String> blockingQueue = null;
	public MySource(BlockingQueue<String> blockingQueue){
		this.blockingQueue = blockingQueue;
		System.out.println(blockingQueue.getClass().getName());//方便日志排查
	}
	
	//生产操作
	public void myProd() throws Exception{
		String data = null;
		boolean returnValue;
		while(FLAG){
			data = atomicInteger.incrementAndGet()+"";
			returnValue = blockingQueue.offer(data,2L,TimeUnit.SECONDS);
			if(returnValue){
				System.out.println(Thread.currentThread().getName()+"\t 插入队列"+data+"成功");
			}else{
				System.out.println(Thread.currentThread().getName()+"\t 插入队列"+data+"失败!");
			}
			TimeUnit.SECONDS.sleep(1);//1秒生产一个
		}
		System.out.println("FLAG==false,此时表示停止生产");
	}
	
	//消费操作
    public void myConsumer() throws Exception{
    	String result = null;
    	while(FLAG){
    		result = blockingQueue.poll(2L,TimeUnit.SECONDS);//超过2秒没有取到,就停止取操作,返回null
    		if(result == null || result.equalsIgnoreCase("")){
    			FLAG = false;
    			System.out.println(Thread.currentThread().getName()+"\t 超过两秒没有取到,消费退出");
    			System.out.println();
    			System.out.println();
    			return;
    		}
    		System.out.println(Thread.currentThread().getName()+"\t 消费队列"+result+"成功");
    	}
    }
    
    //停止方法
    public void stop() throws Exception{
    	this.FLAG = false;
    }
    
}




public class ProConsumer_TroditionDemo {

	public static void main(String[] args) {
		
		MySource mysource = new MySource(new ArrayBlockingQueue<>(10));
		
		// 生产者线程
		new Thread(()->{
			System.out.println(Thread.currentThread().getName()+"\t 生产者线程启动");
			try {
				mysource.myProd();
			} catch (Exception e) {
				e.printStackTrace();
			}
		},"Prod").start();
		
		// 消费者线程
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName()+"\t 消费者线程启动");
			System.out.println();
			try {
				mysource.myConsumer();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}, "Consumer").start();
		
		try {
			Thread.currentThread().sleep(5000);//暂停5秒住线程
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	    
		System.out.println();
		System.out.println();
		System.out.println();
		System.out.println("5秒钟时间到,停止操作");
		
		try {
			mysource.stop();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

}

打印结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值