正常的生产者消费者模式,按多线程的处理思路来,当条件满足的时候生产者通知消费者消费,条件不满足的时候,消费者通知生产者来生产,然后继续消费。这就涉及到线程间通信,前面我说volatile的时候讲过线程间通信有两种方式:一、通过公共变量。二、通过消息传递。volatile就是前者,后者前面也说了,wait(),notify()。就是典型的后者实现。但是wait() 和 notify()使用起来很笨重。下面先来看例子:
一个简单的买票小程序:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class o1condition {
public int count = 10;
synchronized void put(){
try {
while(count == 0){
this.wait();
}
count--;
System.out.println(Thread.currentThread().getName()+"消费了一个,当前还剩余"+count+"个");
this.notifyAll();
} catch (Exception e) {
// TODO: handle exception
}
}
synchronized void add(){
try {
while(count > 0){
this.wait();
}
count++;
System.out.println(Thread.currentThread().getName()+"生产了一个,当前还剩余+"+count);
this.notifyAll();
} catch (Exception e) {
// TODO: handle exception
}
}
public static void main(String [] args){
waitnotify a = new waitnotify();
for(int i=0; i<5; i++){
new Thread(() -> {
while(true){
a.put();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"消费者"+i).start();
}
for(int i=0; i<2; i++){
new Thread(() -> {
while(true){
a.add();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"生产者"+i).start();
}
}
}
程序很简单,五个消费者,两个生产者。当count为0的时候,消费者通知生产者生产,如果count大于0的话,就通知消费者消费自己休息。这样有一个缺点,就是当唤醒的时候这个this会唤醒所有人,正常,如果count>0应该只唤醒消费者,而count = 0的话只需要唤醒生产者生产就可以了,notifyall()会唤醒所有人,这势必要带来系统额外的开销,并且显得不灵活。有没有更好的方法?有,当然有。
Condition
看代码:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import sun.text.resources.CollationData;
public class waitnotify {
public int count = 10;
ReentrantLock lock = new ReentrantLock();
Condition produce = lock.newCondition();
Condition consumer = lock.newCondition();
void put(){
lock.lock();
try {
while(count == 0){
consumer.await();
}
count--;
System.out.println(Thread.currentThread().getName()+"消费了一个,当前还剩余"+count+"个");
produce.signalAll();;
} catch (Exception e) {
// TODO: handle exception
} finally {
lock.unlock();
}
}
void add(){
lock.lock();
try {
while(count > 0){
produce.await();
}
count++;
System.out.println(Thread.currentThread().getName()+"生产了一个,当前还剩余+"+count);
consumer.signalAll();
} catch (Exception e) {
// TODO: handle exception
} finally {
lock.unlock();
}
}
public static void main(String [] args){
waitnotify a = new waitnotify();
for(int i=0; i<5; i++){
new Thread(() -> {
while(true){
a.put();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"消费者"+i).start();
}
for(int i=0; i<2; i++){
new Thread(() -> {
while(true){
a.add();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"生产者"+i).start();
}
}
}
我们可以精确指定消费者和生产者等待或者唤醒,这样比较灵活。
Conditiond需要配合Lock使用,而wait()notify()则需要配合synchronized使用。