JAVA实现生产消费者模型
前言
最近面试比较多,发现生产消费者模型在各公司面试的过程中问的还是比较多的,记录一下常见JAVA实现生产者消费模型的代码
思路
我们通过三种模式来实现
- 通过wait和notify
- 通过Lock和Condition
- 通过JAVA内部的阻塞队列ArrayBlockingQueue
代码
- wait和notify
通过synchronized来保证线程安全,在消息满或者不足的时候wait进行阻塞,然后notifyAll来通知其他监听
static class Storage {
private Queue<Integer> queue;
private Integer max;
public Storage(Queue<Integer> queue, Integer max) {
this.queue = queue;
this.max = max;
}
private synchronized void produce(Integer msg) {
while (queue.size() > max) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.offer(msg);
this.notifyAll();
}
private synchronized Integer consume() {
while (queue.size() == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Integer result = queue.poll();
this.notifyAll();
return result;
}
}
- Lock和Condition
通过Lock来保证线程安全,通过Condition来实现阻塞和通信,在消息队列满的时候,通过notFull的wait和notEmpty的signalAll来阻塞当前生产者并且通知消费者来消费消息,消息队列空的时候同理
static class Storage {
private Queue<Integer> queue;
private Integer max;
private Lock lock;
private Condition notEmpty;
private Condition notFull;
public Storage(Queue<Integer> queue, Integer max) {
this.queue = queue;
this.max = max;
lock = new ReentrantLock();
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
private void produce(Integer msg) {
lock.lock();
try {
while (queue.size() > max) {
notFull.await();
}
queue.offer(msg);
notEmpty.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
private synchronized Integer consume() {
lock.lock();
Integer result = null;
try {
while (queue.size() == 0) {
notEmpty.await();
}
result = queue.poll();
notFull.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return result;
}
}
- 通过JAVA的实现类ArrayBlockingQueue
ArrayBlockingQueue是一个阻塞队列,在队列满的时候put会阻塞,空的时候take也会阻塞,其内部实现也是基于Lock和Condition来实现的
static class Storage {
private ArrayBlockingQueue<Integer> queue;
public Storage(Integer max) {
this.queue = new ArrayBlockingQueue<>(max);
}
private void produce(Integer msg) {
try {
queue.put(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private Integer consume() {
try {
return queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
测试
生产线程:
static class Producer implements Runnable {
private Storage storage;
private Integer msg;
public Producer(Storage storage, Integer msg) {
this.storage = storage;
this.msg = msg;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
storage.produce(msg);
System.out.println("this is producer :" + msg);
}
}
}
消费者线程:
static class Consumer implements Runnable {
private Storage storage;
public Consumer(Storage storage) {
this.storage = storage;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("this is consumer:" + storage.consume());
}
}
}
测试用例:通过多个生产者消费者线程来模拟,执行代码后可验证生产和消费的有序进行
public static void main(String[] args) {
Storage storage = new Storage(2);
Producer producer = new Producer(storage, 1);
Producer producer2 = new Producer(storage, 2);
Producer producer3 = new Producer(storage, 3);
new Thread(producer).start();
new Thread(producer2).start();
new Thread(producer3).start();
Consumer consumer1 = new Consumer(storage);
Consumer consumer2 = new Consumer(storage);
Consumer consumer3 = new Consumer(storage);
new Thread(consumer1).start();
new Thread(consumer2).start();
new Thread(consumer3).start();
}
千里之行,积于跬步;万里之船,成于罗盘,共勉。