介绍生产者消费者模式的四种不同实现
实现1:Object,wait,notifyAll
说明:生成String对象作为锁,通过boolean型变量hasValue来判断队列是否为空
(缺点:队列中仅包含一个对象)
注意:用notifyAll不用notify防止唤醒同类进程而锁住。
// 通过Object对象的wait,notifyAll实现
public class PC {
private String lock ="i am a lock";
private boolean hasValue = false;
public void setValue() {
try {
synchronized (lock) {
while (hasValue) {
System.out.println(Thread.currentThread().getName() + " waiting...");
lock.wait();
}
System.out.println(Thread.currentThread().getName() + " runnable...");
hasValue = true;
lock.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void getValue() {
try {
synchronized (lock) {
while (!hasValue) {
System.out.println(Thread.currentThread().getName() + " waiting...");
lock.wait();
}
System.out.println(Thread.currentThread().getName() + " runnable...");
hasValue = false;
lock.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
PC pc = new PC();
P[] ps = new P[5];
C[] cs = new C[5];
for (int i = 0; i < 5; i++) {
ps[i] = new P(pc);
ps[i].setName("生产者" + (i + 1));
cs[i] = new C(pc);
cs[i].setName("消费者" + (i + 1));
ps[i].start();
cs[i].start();
}
}
}
class P extends Thread {
private PC pc;
public P(PC pc) {
super();
this.pc = pc;
}
@Override
public void run() {
while (true) {
pc.setValue();
}
}
}
class C extends Thread {
private PC pc;
public C(PC pc) {
super();
this.pc = pc;
}
@Override
public void run() {
while (true) {
pc.getValue();
}
}
}
输出:
生产者1 runnable...
生产者1 waiting...
消费者2 runnable...
消费者2 waiting...
消费者1 waiting...
生产者1 runnable...
生产者1 waiting...
消费者2 runnable...
消费者2 waiting...
消费者1 waiting...
生产者3 runnable...
生产者3 waiting...
生产者1 waiting...
消费者3 runnable...
消费者3 waiting...
消费者4 waiting...
生产者2 runnable...
生产者2 waiting...
生产者5 waiting...
消费者1 runnable...
消费者1 waiting...
生产者3 runnable...
生产者3 waiting...
生产者1 waiting...
消费者5 runnable...
消费者5 waiting...
生产者4 runnable...
生产者4 waiting...
...
实现2:Condition,await,signal
说明:生成ReentrantLcok对象作为锁,通过Condition对象控制等待与唤醒,boolean型hasValue判断队列是否为空(缺点:队列中仅包含一个对象)
注意:finally中unlock锁
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
// 通过Condition对象的await,signal实现
public class PC {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean hasValue = false;
public void set() {
try {
lock.lock();
while (hasValue == true) {
System.out.println(Thread.currentThread().getName() + " waiting...");
condition.await();
}
System.out.println(Thread.currentThread().getName() + " runnable...");
hasValue = true;
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void get() {
try {
lock.lock();
while (hasValue == false) {
System.out.println(Thread.currentThread().getName() + " waiting...");
condition.await();
}
System.out.println(Thread.currentThread().getName() + " runnable...");
hasValue = false;
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
PC pc = new PC();
P[] ps = new P[5];
C[] cs = new C[5];
for(int i =0;i<5;i++){
ps[i] = new P(pc);
ps[i].setName("生产者"+(i+1));
cs[i] = new C(pc);
cs[i].setName("消费者"+(i+1));
ps[i].start();
cs[i].start();
}
}
}
class P extends Thread {
private PC pc;
public P(PC pc) {
this.pc = pc;
}
@Override
public void run() {
pc.set();
}
}
class C extends Thread {
private PC pc;
public C(PC pc) {
this.pc = pc;
}
@Override
public void run() {
pc.get();
}
}
输出:
生产者1 runnable...
生产者2 waiting...
消费者1 runnable...
消费者2 waiting...
生产者3 runnable...
消费者3 runnable...
生产者4 runnable...
消费者4 runnable...
生产者5 runnable...
消费者5 runnable...
生产者2 runnable...
消费者2 runnable...
实现3:Queue,wait,signalAll
说明:生成Vector对象作为锁,通过队列size判断队列长度,实现队列中存储多个对象。
import java.util.Vector;
// 通过Object的wait,notifyAll实现
public class PC {
public static void main(String[] args) {
Vector<Integer> shareQueue = new Vector<>();
int size = 2;
Thread p = new Thread(new P(shareQueue, size));
Thread c = new Thread(new C(shareQueue));
p.start();
c.start();
}
}
class P extends Thread {
private final Vector<Integer> shareQueue;
private final int size;
public P(Vector<Integer> shareQueue, int size) {
this.shareQueue = shareQueue;
this.size = size;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
produce(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
// -1 as sentinel
produce(-1);
System.out.println("finish producing ...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void produce(int i) throws InterruptedException {
while (shareQueue.size() == size) {
synchronized (shareQueue) {
System.out.println("queue is full ... " + "waiting to produce " + i);
shareQueue.wait();
}
}
System.out.println("produce ... " + i);
synchronized (shareQueue) {
shareQueue.add(i);
shareQueue.notifyAll();
}
}
}
class C extends Thread {
private final Vector<Integer> shareQueue;
public C(Vector<Integer> shareQueue) {
this.shareQueue = shareQueue;
}
@Override
public void run() {
while (true) {
try {
while (shareQueue.isEmpty()) {
synchronized (shareQueue) {
System.out.println("queue is empty ...");
shareQueue.wait();
}
}
synchronized (shareQueue) {
shareQueue.notifyAll();
int i = shareQueue.remove(0);
if (i == -1) {
System.out.println("finish consuming ...");
return;
}
System.out.println("consume ... " + i);
}
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出:
queue is empty ...
produce ... 0
produce ... 1
consume ... 0
produce ... 2
queue is full ... waiting to produce 3
consume ... 1
produce ... 3
queue is full ... waiting to produce 4
consume ... 2
produce ... 4
queue is full ... waiting to produce -1
consume ... 3
produce ... -1
finish producing ...
consume ... 4
finish consuming ...
实现4:BlockingQueue,put,take
说明:java.util.concurrent.BlockingQueue封装了ReentrantLock,操作简单
注意:输出不同步会有一些错误,但内部实现是没有问题的,可参考ArrayBlockingQueue源码put,take的实现。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
// 通过BlockingQueue的put,take实现
public class PC {
private static final int capacity = 2;
private static BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(capacity);
static class P extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
queue.put(i);
System.out.println("produce ... " + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class C extends Thread {
@Override
public void run() {
while (true) {
try {
while (!queue.isEmpty()) {
int take = queue.take();
System.out.println("consume... " + take);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
try {
P p = new P();
p.start();
Thread.sleep(10);
C c = new C();
c.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出:
produce ... 0
produce ... 1
consume... 0
consume... 1
consume... 2
produce ... 2
produce ... 3
produce ... 4
produce ... 5
consume... 3
consume... 4
produce ... 6
consume... 5
consume... 6
consume... 7
produce ... 7
produce ... 8
produce ... 9
consume... 8
consume... 9