生产者-消费者问题
实现目标:
- 两类线程
生产者线程生产数据
消费者线程消费数据 - 共享的数据区域
如果共享数据区已满,阻塞生产者继续生产数据放置入内;
如果共享数据区为空,阻塞消费者继续消费数据;
在实现生产者消费者问题时,可以采用三种方式:
- 使用 Object 的 wait/notify 的消息通知机制;
- 使用 Lock 的 Condition 的 await/signal 的消息通知机制;
- 使用 BlockingQueue 实现。
一、使用 Object 的 wait/notify 的消息通知机制
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ObjectWaitNotifyDemo {
static class Productor implements Runnable{
private LinkedList<Integer> list;
private int maxLength;
private Random random;
public Productor(LinkedList<Integer> linkedList,int maxLength){
this.list = linkedList;
this.maxLength = maxLength;
random = new Random();
}
@Override
public void run() {
while (true){
synchronized(list){
try{
while (list.size()==maxLength){
System.out.println("生产者"+Thread.currentThread().getName()+" list达到最大,进行wait()");
list.wait();
System.out.println("生产者"+Thread.currentThread().getName()+" wait()结束");
}
int p = random.nextInt();
System.out.println("生产者"+Thread.currentThread().getName()+"生产了"+p);
list.add(p);
list.notifyAll();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
static class Consumer implements Runnable{
private LinkedList<Integer> list;
public Consumer(LinkedList<Integer> linkedList){
this.list = linkedList;
}
@Override
public void run() {
while (true){
synchronized (list){
try {
while (list.isEmpty()){
System.out.println("消费者"+Thread.currentThread().getName()+" list为空,进行wait()");
list.wait();
System.out.println("消费者"+Thread.currentThread().getName()+" wait()结束");
}
Integer p = list.remove(0);
System.out.println("消费者"+Thread.currentThread().getName()+"消费了"+p);
list.notifyAll();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
ExecutorService service = Executors.newFixedThreadPool(15);
for (int i = 0; i < 5; i++) {
service.submit(new Productor(list,10));
}
for (int i = 0; i < 10; i++) {
service.submit(new Consumer(list));
}
}
}
二、使用 Lock 的 Condition 的 await/signal 的消息通知机制
await 放入conditon对应的等待队列
signal 唤醒等待队列的线程到同步队列
import javax.print.DocFlavor;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockConditionDemo {
private static ReentrantLock lock = new ReentrantLock();
private static Condition full = lock.newCondition();
private static Condition empty = lock.newCondition();
static class Productor implements Runnable{
private LinkedList<Integer> list;
private int maxLength;
private Random random;
private Lock lock;
public Productor(LinkedList<Integer> linkedList,int maxLength,Lock lock){
this.list = linkedList;
this.maxLength = maxLength;
this.lock = lock;
random = new Random();
}
@Override
public void run() {
while (true){
lock.lock();
try{
while (list.size()==maxLength){
System.out.println("生产者"+Thread.currentThread().getName()+" list满了,进行await");
full.await();
System.out.println("生产者"+Thread.currentThread().getName()+" 结束await");
}
int p = random.nextInt();
System.out.println("生产者"+Thread.currentThread().getName()+" 生产了"+p);
list.add(p);
empty.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
static class Consumer implements Runnable{
private LinkedList<Integer> list;
private Lock lock;
public Consumer(LinkedList<Integer> linkedList,Lock lock){
this.list = linkedList;
this.lock = lock;
}
@Override
public void run() {
while (true){
lock.lock();
try{
while (list.isEmpty()){
System.out.println("消费者"+Thread.currentThread().getName()+" list空了,开始await");
empty.await();
System.out.println("消费者"+Thread.currentThread().getName()+" 结束await");
}
int p = list.remove(0);
System.out.println("消费者"+Thread.currentThread().getName()+" 消费了"+p);
full.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
public static void main(String[] args) {
LinkedList<Integer> linkedList = new LinkedList<>();
ExecutorService service = Executors.newFixedThreadPool(15);
for (int i = 0; i < 5; i++) {
service.submit(new Productor(linkedList,10,lock));
}
for (int i = 0; i < 10; i++) {
service.submit(new Consumer(linkedList,lock));
}
}
}
三、使用 BlockingQueue 实现
由于 BlockingQueue 内部实现就附加了两个阻塞操作。即当队列已满时,阻塞向队列中插入数据的线程,直至队列中未满;当队列为空时,阻塞从队列中获取数据的线程,直至队列非空时为止。
可以利用 BlockingQueue 实现生产者-消费者为题,阻塞队列完全可以充当共享数据区域,就可以很好的完成生产者和消费者线程之间的协作。
put/take
import java.util.Random;
import java.util.concurrent.*;
public class BlockQueueDemo {
private static LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
static class Productor implements Runnable{
private BlockingQueue queue;
private Random random;
public Productor(LinkedBlockingQueue<Integer> queue){
this.queue = queue;
random = new Random();
}
@Override
public void run() {
while (true){
try {
int p = random.nextInt();
System.out.println("生产者"+Thread.currentThread().getName()+" 生产了"+p);
queue.put(p);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class Consumer implements Runnable{
private BlockingQueue queue;
public Consumer(LinkedBlockingQueue<Integer> queue){
this.queue = queue;
}
@Override
public void run() {
while (true){
try {
Integer p = (Integer) queue.take();
System.out.println("消费者"+Thread.currentThread().getName()+" 消费了"+p);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(15);
for (int i = 0; i < 5; i++) {
service.submit(new Productor(queue));
}
for (int i = 0; i < 10; i++) {
service.submit(new Consumer(queue));
}
}
}