生产者消费者模式的三种写法(面试题常考)

我们通常在面试中大量遇到的手撕代码的题无非就是以下几种:
死锁,几种排序算法(最常考的快速排序,归并排序),生产者消费者模式,单例模式
在多线程这边,我们通常需要掌握生产者消费者模式,生产者消费者模式我们可以用sychronized版本写,更加高阶的可以用Reentranlock版本+condition(条件变量)来写。
为了达到精准通知的目的,我们还可以使用ReentrantLock版本+多个condition(条件变量来写)。

sychronized版本:

public class Demo01 {
	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(); 
		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 Data{
	
	private int number = 0;//定义初始数量为0
	
	public synchronized void increment() throws InterruptedException {
		while(number !=0) {
			this.wait();
		}
		
		number++;
		System.out.println(Thread.currentThread().getName()+"=>"+number);
		//通知其他线程,我自增完了
		this.notifyAll();
	}
	
	public synchronized void decrement() throws InterruptedException {
		while(number == 0) {
			this.wait();
		}
		number--;
		System.out.println(Thread.currentThread().getName()+"=>"+number);
		//通知其他线程,我自增完了
		this.notifyAll();
	}
	
}

ReentrantLock +单个condition(条件变量版本)

public class Demo01 {
	public static void main(String[] args) {
			Data data = new Data();
		
		new Thread(()->{
			for(int i =0;i<10;i++) {
				data.increment();
			}
		},"线程A").start(); 
		
		new Thread(()->{
			for(int i =0;i<10;i++) {
				data.decrement();
			}
		},"线程B").start(); 
		new Thread(()->{
			for(int i =0;i<10;i++) {
				data.increment();
			}
		},"线程C").start(); 
		new Thread(()->{
			for(int i =0;i<10;i++) {
				data.decrement();
			}
		},"线程D").start(); 
	}

}

class Data{
	private int number = 0;
	//创建lock锁
	Lock lock = new ReentrantLock();
	//通过kock锁建立条件变量
	Condition condition = lock.newCondition();
	
	//+1
	public void increment() {
		lock.lock();
		try {
			//业务代码
			while(number !=0) {
				condition.await();
			}
			number++;
			System.out.println(Thread.currentThread().getName()+"=>"+number);
			//通知其他线程,我+1完毕了
			condition.signalAll();
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}
	
	//-1
	public void decrement() {
		lock.lock();
		try {
			//业务代码
			while(number ==0) {
				condition.await();
			}
			number--;
			System.out.println(Thread.currentThread().getName()+"=>"+number);
			//通知其他线程,我-1完毕了
			condition.signalAll();
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}
}

但是上述代码会出现一个问题,那就是通知的情况是随机性的,我们如果要达到精准通知的目的,我们需要用多个condition来达到精准通知的效果!
ReentrantLock +多个condition(条件变量版本)

package RentrantLockDemo;

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

public class Demo02 {
	public static void main(String[] args) {
		Data03 data =new Data03();
		
		new Thread(()->{
			for(int i =0;i<10;i++) {
				data.printA();
			}
		},"线程A").start();
		new Thread(()->{
			for(int i =0;i<10;i++) {
				data.printB();
			}
		},"线程B").start();
		new Thread(()->{
			for(int i =0;i<10;i++) {
				data.printC();
			}
		},"线程C").start();
	}
	
}

class Data03{
	
	//定义初始 的票数
	private int number =1;//当为1的时候唤醒打印A,当为2的时候唤醒打印B,当为3的时候唤醒打印C
	
	private Lock lock = new ReentrantLock();
	private Condition condition1 = lock.newCondition();
	private Condition condition2 = lock.newCondition();
	private Condition condition3 = lock.newCondition();
	
	public void printA() {
		lock.lock();
		try {
			//业务逻辑
			while(number!=1) {
				condition1.await();
			}
			System.out.println(Thread.currentThread().getName()+"=>AAAAAAAAAAA");
			number =2;
			condition2.signal();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}
	
	public void printB() {
		lock.lock();
		try {
			while(number!=2) {
				condition2.await();
			}
			System.out.println(Thread.currentThread().getName()+"=>BBBBBBBBBBBB");
			number =3;
			condition3.signal();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}
	
	public void printC() {
		lock.lock();
		try {
			while(number!=3) {
				condition3.await();
			}
			System.out.println(Thread.currentThread().getName()+"=>ccccccccc");
			number =1;
			condition1.signal();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}
	
	
	
}

为了秋招更好的复习,所以会经常和大家分享一些平时的学习所得,如果有错误,也请大家指正!感谢大家!

你可能感兴趣的:(生产者消费者模式的三种写法(面试题常考))