java面试系列--J2SE基础(八)

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

24. 写出生产者消费者模式。

生产者消费者模式介绍:

生产者生产数据到缓冲区中,消费者从缓冲区中取数据。

如果缓冲区已经满了,不能继续生产,则生产者线程阻塞等待,直到有空闲缓冲区可供继续生产;
如果缓冲区为空,不能继续消费,则消费者线程阻塞等待,直到缓冲区有新产生可供消费。

常见场景:

比如厂家生产一批东西到商场,顾客消费者到商场买东西,厂家即为生产者,商场即为缓冲区,顾客即为消费者。


缓冲区作用:

1. 解耦,生产者和消费者不直接建立关系,都只依赖缓冲区,而不互相依赖
2. 独立运作,支持并发和异步,提升效率

常见的生产者消费者几种实现方式:

方式一:synchronized同步锁,同步队列,配合wait、notifyAll

package com.ws.synchroniz;

import java.util.LinkedList;
import java.util.Queue;
/**
 * 
 * @author WeiS
 *
 */
public class MessageQueue {
	
	private static final int size = 10;
	private Queue<Integer> messageQueue = new LinkedList<>();
	
	public void put(Integer num) {
		synchronized (messageQueue) {
            while (messageQueue.size() > size) {
                System.err.println(Thread.currentThread().getId() + "等待....[" + num + "]");
                try {
                	messageQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            messageQueue.add(num);
            System.err.println(Thread.currentThread().getId() + "放入[" + num + "]");
            messageQueue.notifyAll();
        }
	}
	
	public Integer get() {
		Integer take = 0;
		synchronized (messageQueue) {
			while (messageQueue.isEmpty()) {
				System.err.println(Thread.currentThread().getId() + "等待....");
				try {
					messageQueue.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			take = messageQueue.poll();
			System.err.println(Thread.currentThread().getId() + "移除[" + take + "]");
			messageQueue.notifyAll();
		}
		return take;
	}

}

方式二:重入锁ReentrantLock、配合Condition、await、signalAll

package com.ws.lock;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 
 * @author WeiS
 *
 */
public class MessageQueue {
	
	private static final int size = 10;
	private Queue<Integer> messageQueue = new LinkedList<>();
	private final Lock reentrantLock = new ReentrantLock();
    private final Condition putCondition = reentrantLock.newCondition();
    private final Condition getCondition = reentrantLock.newCondition();
	
	public void put(Integer num) {
		reentrantLock.lock();
		while (messageQueue.size() > size) {
			System.err.println(Thread.currentThread().getId() + "..生产等待....[" + num + "]");
			try {
				putCondition.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		messageQueue.add(num);
		System.err.println(Thread.currentThread().getId() + "放入[" + num + "]");
		getCondition.signalAll();
		reentrantLock.unlock();
	}
	
	public Integer get() {
		reentrantLock.lock();
		Integer take = 0;
		while (messageQueue.isEmpty()) {
			System.err.println(Thread.currentThread().getId() + "..消费等待....");
			try {
				getCondition.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		take = messageQueue.poll();
		System.err.println(Thread.currentThread().getId() + "移除[" + take + "]");
		putCondition.signalAll();
		reentrantLock.unlock();
		return take;
	}

}

方式三:阻塞队列BlockingQueue

package com.ws;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
 * 
 * @author WeiS
 *
 */
public class MessageQueue {
	
	private static final int size = 10;
	private BlockingQueue<Integer> messageQueue = new LinkedBlockingQueue<>(size);
	
	public void put(Integer num) {
		try {
			messageQueue.put(num);
			System.err.println(Thread.currentThread().getId() + "放入[" + num + "]");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public Integer get() {
		Integer take = 0;
		try {
			take = messageQueue.take();
			System.err.println(Thread.currentThread().getId() + "移除[" + take + "]");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return take;
	}

}

其他生产者、消费者代码参考如下:(可通用)

package com.ws.lock;

import java.util.Random;
/**
 * 
 * @author WeiS
 *
 */
public class Producer extends Thread{
	
	private MessageQueue messageQueue;
	
	public Producer(MessageQueue messageQueue) {
		super();
		this.messageQueue = messageQueue;
	}

	@Override
	public void run() {
		while(true) {
			try {
				Thread.sleep((long) (1000 * Math.random()));
				int nextInt = new Random().nextInt(10000);
				//System.out.println(Thread.currentThread().getId() + "生产[" + nextInt + "]");
				messageQueue.put(nextInt);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}

}

package com.ws.lock;
/**
 * 
 * @author WeiS
 *
 */
public class Consumer extends Thread{
	
	private MessageQueue messageQueue;
	
	public Consumer(MessageQueue messageQueue) {
		super();
		this.messageQueue = messageQueue;
	}

	@Override
	public void run() {
		while(true) {
			try {
				Thread.sleep((long) (1000 * Math.random()));
				@SuppressWarnings("unused")
				Integer integer = messageQueue.get();
				//System.out.println(Thread.currentThread().getId() + "消费[" + integer + "]");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}

}

package com.ws.lock;

public class Main {
	
	public static void main(String[] args) {
		MessageQueue messageQueue = new MessageQueue();
		Producer producer = new Producer(messageQueue);
		
		Consumer consumer = new Consumer(messageQueue);
		Consumer consumer1 = new Consumer(messageQueue);
		Consumer consumer2 = new Consumer(messageQueue);
		
		producer.start();
		consumer.start();
		consumer1.start();
		consumer2.start();
		
	}
	

}

下图可以看下这个阻塞队列的继承过程:

(可点击图片放大查看)


打赏

如果觉得我的文章对你有帮助,有钱就捧个钱场,没钱就捧个人场,欢迎点赞或转发 ,并请注明原出处,谢谢....








猜你喜欢

转载自blog.csdn.net/weisong530624687/article/details/79293297