生产者消费者模式
一、synchronized同步
public class PcSync {
static int MAX = 10;
static Queue<Object> queue = new ArrayDeque<>(MAX);
public static void main(String[] args) {
Producer p = new Producer();
Consumer c1 = new Consumer();
Consumer c2 = new Consumer();
new Thread(p).start();
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
static class Producer implements Runnable {
@Override
public void run() {
while (true) {
synchronized (PcSync.class) {
if (queue.size() < MAX) {
queue.add(new Object());
System.out.println("生产一个,生产后有商品" + queue.size() + "个");
SleepTools.randomMs(400);
} else {
System.out.println("满了,不能再生产了...");
}
}
}
}
}
static class Consumer implements Runnable {
@Override
public void run() {
while (true) {
synchronized (PcSync.class) {
if (queue.size() > 0) {
queue.remove();
System.out.println("消费一个,消费后有商品" + queue.size() + "个");
SleepTools.randomMs(400);
} else {
System.out.println("空了,不能再消费了...");
}
}
}
}
}
}
二、wait-notify
public class PcWaitNotify {
static int MAX = 10;
static Queue<Object> queue = new ArrayDeque<>(MAX);
public static void main(String[] args) {
Producer p = new Producer();
Consumer c1 = new Consumer();
Consumer c2 = new Consumer();
new Thread(p).start();
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
static class Producer implements Runnable {
@Override
public void run() {
while (true) {
synchronized (queue) {
if (queue.size() >= MAX) {
queue.notifyAll();
} else {
queue.add(new Object());
System.out.println("生产者生产了 1 个,现在有:" + queue.size() + " 个商品...");
SleepTools.randomMs(500);
}
}
}
}
}
static class Consumer implements Runnable {
@Override
public void run() {
while (true) {
synchronized (queue) {
if (queue.size() <= 0) {
queue.notifyAll();
} else {
queue.remove();
System.out.println("消费者消费了 1 个,现在有:" + queue.size() + " 个商品...");
SleepTools.randomMs(500);
}
}
}
}
}
}
三、Condition
public class PcCondition {
private static ReentrantLock lock = new ReentrantLock();
private static Condition consumer = lock.newCondition();
private static Condition producer = lock.newCondition();
private static LinkedList<Object> buffer = new LinkedList<>();
private static final int MAX = 5;
public static void main(String[] args) {
new Thread(new Producer()).start();
new Thread(new Producer()).start();
new Thread(new Consumer()).start();
new Thread(new Consumer()).start();
}
static class Producer implements Runnable {
@Override
public void run() {
while (true) {
lock.lock();
try {
while (buffer.size() >= MAX) {
System.out.println("满了...");
try {
producer.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (buffer.size() < MAX) {
buffer.add(new Object());
System.out.println("生产一个...生产后数量是" + buffer.size());
consumer.signalAll();
SleepTools.randomMs(5000);
}
} finally {
lock.unlock();
}
SleepTools.randomMs(5);
}
}
}
static class Consumer implements Runnable {
@Override
public void run() {
while (true) {
lock.lock();
try {
while (buffer.size() <= 0) {
System.out.println("空了...");
try {
consumer.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (buffer.size() > 0) {
buffer.removeFirst();
System.out.println("消费一个...消费后数量是" + buffer.size());
producer.signalAll();
SleepTools.randomMs(5000);
}
} finally {
lock.unlock();
}
}
}
}
}
四、同步队列
public class Pc {
private static AtomicInteger integer = new AtomicInteger(0);
public static void main(String[] args) {
BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<>(100);
Producer p = new Producer(blockingQueue);
Consumer c1 = new Consumer(blockingQueue);
Consumer c2 = new Consumer(blockingQueue);
new Thread(p).start();
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
static class Producer implements Runnable {
BlockingQueue<Integer> blockingQueue;
Producer(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
while (true) {
int i = integer.getAndIncrement();
blockingQueue.add(i);
System.out.println("生产者生产商品,编号为" + i);
SleepTools.randomMs(5000);
}
}
}
static class Consumer implements Runnable {
BlockingQueue<Integer> blockingQueue;
Consumer(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
while (true) {
Integer element = null;
try {
element = blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者消费一个,编号为" + element);
SleepTools.randomMs(5000);
}
}
}
}
五、有bug的情况
public class PcConditionBug {
private static ReentrantLock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
private static LinkedList<Object> buffer = new LinkedList<>();
private static final int MAX = 5;
public static void main(String[] args) {
new Thread(new Producer()).start();
new Thread(new Producer()).start();
new Thread(new Consumer()).start();
new Thread(new Consumer()).start();
}
static class Producer implements Runnable {
@Override
public void run() {
while (true) {
lock.lock();
try {
while (buffer.size() >= MAX) {
System.out.println("满了...");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (buffer.size() < MAX) {
buffer.add(new Object());
System.out.println("生产一个...生产后数量是" + buffer.size());
condition.signal();
SleepTools.randomMs(50);
}
} finally {
lock.unlock();
}
}
}
}
static class Consumer implements Runnable {
@Override
public void run() {
while (true) {
lock.lock();
try {
while (buffer.size() <= 0) {
System.out.println("空了...");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (buffer.size() > 0) {
buffer.removeFirst();
System.out.println("消费一个...消费后数量是" + buffer.size());
condition.signal();
SleepTools.randomMs(50);
}
} finally {
lock.unlock();
}
}
}
}
}
对比
方案 | 优点 | 缺点 |
---|
synchronized | 代码简单,方法被同步执行,线程安全 | 相对没那么灵活 |
wait-notify | 容易学习了解同步机制 | 需要注意死锁的情况,用singal要小心 |
Condition | 容易控制 | 注意自由一个Condition的时候有可能会死锁 |
同步队列 | 不需要考虑线程安全,线程安全容器实现了线程间的同步,编码简单 | 不利于了解同步细节 |
- 如果要实现安全高效的,建议使用同步队列,另外双Condition也很好