您的位置:首页 > 编程语言 > Java开发

用Condition条件变量实现生产者消费者模式

2016-04-01 17:40 477 查看
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumerPattern{
public static final int MAX_CAP = 20;
static LinkedList<Object> list = new LinkedList<Object>();
static ReentrantLock lock = new ReentrantLock();
static Condition notFull = lock.newCondition();
static Condition notEmpty = lock.newCondition();

static class Producer implements Runnable {

@Override
public void run() {
while(true) {
try {
lock.lock();
while(list.size() == MAX_CAP) {
try {
System.out.println("当前已有"+list.size()+"个产品,缓冲区已满,请等待消费者消费");
notFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add(new Object());
System.out.println("生产了一个产品,当前产品个数为 " + list.size());
notEmpty.signalAll();
} finally {
lock.unlock();
}
Thread.yield();
}
}
}

static class Consumer implements Runnable {

@Override
public void run() {
while(true) {
try {
lock.lock();
while(list.size() == 0) {
try {
System.out.println("当前已有"+list.size()+"个产品,缓冲区已空,请等待生产者生产");
notEmpty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.remove();
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费了一个产品,当前产品个数为 " + list.size());
notFull.signalAll();
} finally {
lock.unlock();
}
Thread.yield();
}
}
}
public static void main(String[] args) throws InterruptedException {

4000
for(int i=0; i<3; i++) {
new Thread(new Producer()).start();
}
for(int i=0; i<3; i++) {
new Thread(new Consumer()).start();
}
}
}

部分输出结果如下:

生产了一个产品,当前产品个数为 11

生产了一个产品,当前产品个数为 12

生产了一个产品,当前产品个数为 13

消费了一个产品,当前产品个数为 12

消费了一个产品,当前产品个数为 11

消费了一个产品,当前产品个数为 10

消费了一个产品,当前产品个数为 9

…………………………(省略部分输出)

生产了一个产品,当前产品个数为 16

生产了一个产品,当前产品个数为 17

生产了一个产品,当前产品个数为 18

生产了一个产品,当前产品个数为 19

消费了一个产品,当前产品个数为 18

生产了一个产品,当前产品个数为 19

生产了一个产品,当前产品个数为 20

当前已有20个产品,缓冲区已满,请等待消费者消费

当前已有20个产品,缓冲区已满,请等待消费者消费

消费了一个产品,当前产品个数为 19

消费了一个产品,当前产品个数为 18

消费了一个产品,当前产品个数为 17

 

       总结:用条件变量与用wait和notify/notifyAll实现这个模式有一个不同之处在于,Condition的signalAll方法只能唤醒在某一条件上进行阻塞的线程,比如notEmpty.signalAll()只能唤醒通过notEmpty.await()方法而阻塞的线程,在这个例子中的话也就是说生产者调用notEmpty.signalAll()只能唤醒消费者线程,而notifyAll()会唤醒所有在同一个对象锁(Object monitor)上进行等待的线程,比如说生产者和消费者都会因争夺缓冲区对象的锁而导致阻塞,同时在缓冲区满时生产者会调用wait方法进行阻塞,在缓冲区空时消费者会调用wait方法进行阻塞,一旦有线程(不管是生产者还是消费者)调用了notifyAll()方法,则所有的阻塞在同一个Object
monitor上的线程都会被唤醒。也就是说Condition的signalAll()是基于某个条件变量进行唤醒,notifyAll是基于某个对象锁(Object monitor)进行唤醒。

        以上总结纯属个人的体会,可能有误。关于这两种实现方式的详细差别,以后再作深入学习。水平有限,如有不当之处,还望指正!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息