一:概念
1:生产者负责产生数据,消费者负责处理数据。所以消费者需要获得生产者的数据。
2:如果直接让生产者调用消费者的函数来传送数据会产生以下问题:
(1)生产者会依赖消费者。如果消费者的代码发生变化,可能会影响生产者。
(2)由于函数调用是同步的。所以在调用的消费者函数没返回时,生产者只能等待,不能生产数据。
3:所以利用一个缓冲区,生产者将数据放入缓冲区,消费者从中获取数据。这样就可以解决上边的两个问题。
(1)生产者和消费者之间没有直接关系,互相的代码修改互不影响。
(2)生产者向缓冲区存放数据就行,不需要等待消费者处理数据。
二:实例
import java.util.LinkedList;
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;
/*
* 生产者消费者问题
* 1:生产者不能向满的缓冲区写。
* 2:消费者不能从空的缓冲区读。
* 3:同时只能有一个生产者写,同时只能有一个消费者读。
*/
public class Executer {
private ExecutorService pool;
private static Buffer buffer = new Buffer();
public Executer(int num){
pool = Executors.newFixedThreadPool(num);
}
public void execute(Thread t){
pool.execute(t);
}
public static void main(String[] args){
Executer executer = new Executer(3);
//生产者和消费者通过共享的缓冲区中的静态变量进行通信写作完成同步
executer.execute(new Producer());
executer.execute(new Consumer());
executer.execute(new Consumer());
executer.pool.shutdown();
}
private static class Producer extends Thread{
public void run(){
while(true)
System.out.println("consumer consume "+buffer.read());
}
}
private static class Consumer extends Thread{
int i=1;
public void run(){
while(true){
System.out.println("producer produce "+i);
buffer.write(i++);
}
}
}
private static class Buffer{
private static final int CAPACITY = 10;
private LinkedList<Integer> queue = new LinkedList<>();
private static Lock lock = new ReentrantLock();
private static Condition notEmpty = lock.newCondition();
private static Condition notFull = lock.newCondition();
public void write(int value){
lock.lock(); //临界区,每次只能有一个线程进入
try{
while(queue.size() == CAPACITY){ //缓冲区满
System.out.println("wait for notfull condition");
notFull.await();
}
queue.offer(value); //写入
notEmpty.signal();
}catch (Exception e) {
// TODO: handle exception
}finally{
lock.unlock(); //离开临界区
}
}
@SuppressWarnings("finally")
public int read(){
int value = 0;
lock.lock(); //临界区,每次只能有一个线程进入
try{
while(queue.isEmpty()){ //缓冲区空
System.out.println("wait for notEmpty condition");
notEmpty.await();
}
value = queue.remove();
notFull.signal();
}catch (Exception e) {
// TODO: handle exception
}finally{
lock.unlock(); //离开临界区
return value;
}
}
}
}