生产者消费者一共有五种方式可以进行实现:
-
wait() / notify()方法
-
await() / signal()方法
-
BlockingQueue阻塞队列方法
-
Semaphore方法
-
PipedInputStream / PipedOutputStream**
1、wait() / notify()方法
代码示例:
/**
* description: 通过 Wait 和 Notify 来实现生产者消费者
* Created: 2018-11-29 12:21
**/
public class WaitNotifyModel {
//容器中的对象的数量
private Integer count = 0;
//容器的总大小
private Integer FULL ;
//作为锁的对象
private String lock = "LOCK";
WaitNotifyModel(int num) {
FULL= num;
}
//生产者
class producer implements Runnable {
@Override
public void run() {
synchronized (lock){
try {
while (count == FULL){
lock.wait();
}
count++;
System.out.println(Thread.currentThread().getName() + "生产者生产,目前总共有" + count);
lock.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace(); }
}
}
}
//消费者
class consumer implements Runnable {
@Override
public void run() {
synchronized (lock){
try {
while (count == 0){
lock.wait();
}
count--;
System.out.println(Thread.currentThread().getName() + "消费者消费,目前总共有" + count);
lock.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace(); }
}
}
}
}
2、await() / signal()方法
代码示例:
/**
* description: 通过 Lock 和 Condition 来实现生产者消费者
**/
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockConditionMode {
//容器中的对象的数量
private Integer count = 0;
//容器的总大小
private Integer FULL ;
//创建锁进行同步
private Lock lock = new ReentrantLock();
private Condition producerCondition = lock.newCondition();
private Condition consumerCondition = lock.newCondition();
//构造方法,指定容器的大小
LockConditionMode(int num) {
FULL= num;
}
//生产者
class producer implements Runnable {
@Override
public void run() {
//加锁
lock.lock();
try {
//这里使用 while 而不是 if 是为了避免过早或者意外的通知
while (count == FULL) {
//容器满了,生产者阻塞
producerCondition.await();
}
count++;
System.out.println(Thread.currentThread().getName() + "生产者生产,目前总共有" + count);
//唤醒消费者进行消费
consumerCondition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
//消费者
class consumer implements Runnable {
@Override
public void run() {
lock.lock();
try {
while (count == 0) {
//容器空了,消费者阻塞
consumerCondition.await();
}
count--;
System.out.println(Thread.currentThread().getName() + "消费者消费,目前总共有" + count);
producerCondition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
3、Semaphore方法
注意点:
1、生产者和消费者的许可证获取必须要在互斥锁的许可证之前进行获取。
例如下面的许可证的获取顺序不能颠倒:
//顺序不能颠倒,否则会造成死锁。
producerSemaphore.acquire();
mutex.acquire();
因为如果生产者和消费者的许可证在互斥锁的许可证的之后获取,那么会出现,当队列已满时,线程先获取了互斥锁的许可证,而无法获取生产者的许可证,从而被阻塞。
而此时消费者想消费队列中的元素,却因为无法获取互斥锁的许可证,从而只能进行等待,这样就造成了死锁。
2、使用互斥锁保证每次最多只有一个角色去修改共享变量。
代码示例:
/**
* description: 通过 Semaphore 来实现生产者消费者
* Created: 2018-11-29 12:21
**/
public class SemaphoreMode {
private int count = 0;
//生产者的许可证
Semaphore producerSemaphore = new Semaphore(10);
//消费者的许可证
Semaphore consumerSemaphore = new Semaphore(0);
//互斥锁的许可证,使用互斥锁保证每次最多只有一个角色去修改共享变量
Semaphore mutex = new Semaphore(1);
//生产者
class producer implements Runnable{
@Override
public void run() {
try {
//顺序不能颠倒,否则会造成死锁。先获取生产的许可证,再获取独占所的许可证
producerSemaphore.acquire();
mutex.acquire();
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//归还独占锁、消费者的许可证
mutex.release();
consumerSemaphore.release();
}
}
}
//消费者
class consumer implements Runnable{
@Override
public void run() {
try {
//顺序不能颠倒,否则会造成死锁。先获取生产的许可证,再获取独占所的许可证
consumerSemaphore.acquire();
mutex.acquire();
count--;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
mutex.release();
producerSemaphore.release();
}
}
}
}