通过使用Condition提供的await和signal/signalAll方法就可以实现等待/通知机制,而这种机制能够解决最经典的问题就是“生产者与消费者问题”。
await和signal和signalAll方法就像一个开关控制着线程A(等待方)和线程B(通知方)。它们之间的关系可以用下面一个图来表现得更加贴切:

线程awaitThread先通过lock.lock()方法获取锁成功后调用了condition.await方法进入等待队列,而另一个线程signalThread通过lock.lock()方法获取锁成功后调用了condition.signal或者signalAll方法,使得线程awaitThread能够有机会移入到同步队列中,当其他线程释放lock后使得线程awaitThread能够有机会获取lock,从而使得线程awaitThread能够从await方法中退出执行后续操作。如果awaitThread获取lock失败会直接进入到同步队列。
我们用一个很简单的例子说说condition的用法:
妈妈负责做馒头,大林和小林负责吃馒头,厨房有个锅,锅最多放10个馒头,妈妈一共做100个馒头就结束。 使用多线程实现生产者与消费者的多线程例子。统计大林和小林各吃了多少个馒头?
实现代码如下:
public class ProducerConsumeGameLock {
public static void main(String[] args) {
Pot pot = new Pot();
Producer mother = new Producer(pot);
Consumer bigSon = new Consumer(pot,"大林");
Consumer smallSon = new Consumer(pot,"小林");
Thread motherTh = new Thread(mother);
Thread bigSonTh = new Thread(bigSon);
Thread smallSonTh = new Thread(smallSon);
//分别启动三个
motherTh.start();
bigSonTh.start();
smallSonTh.start();
//等待三个线程都结束
try{
motherTh.join();
bigSonTh.join();
smallSonTh.join();
}catch(Exception ex){
ex.printStackTrace();
}
pot.showResult();
}
}
final class Consumer implements Runnable {
private String name;
private Pot pot;
public Consumer(Pot pot,String name ) {
this.name = name;
this.pot = pot;
}
@Override
public void run() {
//儿子不停的吃馒头
while (true) {
if (Pot.COUNT >= 100 && pot.getPot().size() == 0) {
break;
}
//注意:lock和unlock一定是成对出现。
pot.getLock().lock();
pot.eatCake(this.name);
pot.getLock().unlock();
//休眠50毫秒
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
final class Producer implements Runnable {
private Pot pot;
public Producer(Pot pot) {
this.pot = pot;
}
@Override
public void run() {
//妈妈不停的做馒头
while(true){
if (Pot.COUNT >= 100) {
System.out.println("100个馒头做完了,妈妈线程结束!");
break;
}
pot.getLock().lock();
pot.makeCake();
pot.getLock().unlock();
//休眠50毫秒
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//锅类
public class Pot {
private Stack<Integer> pot = new Stack<Integer>();
public static final int MAX_NUMBER = 100; //妈妈一共做100个馒头,程序就结束了。
public volatile static int COUNT = 0;
public static final int MAX_LEN = 10;
private final ReentrantLock lock = new ReentrantLock();
private Condition noCake = lock.newCondition(); //锅里没有馒头的条件
private Condition fullCake = lock.newCondition(); //锅馒头做满时的条件
private int bigSonNum; //大儿子吃的数量
private int smallSonNum; //小儿子吃的数量
public Stack<Integer> getPot() {
return pot;
}
public ReentrantLock getLock() {
return lock;
}
public Condition getNoCake() {
return noCake;
}
public void setFullCake(Condition fullCake) {
this.fullCake = fullCake;
}
//锅里面取馒头的方法
public void eatCake(String name) { // 消费者从锅里面取馒头
try {
if (pot.size() <= 0 && Pot.COUNT < 100) {
System.out.println(name + "锅空了,等待妈妈做馒头!");
noCake.await(); // wait();
}
if (pot.size() > 0) {
System.out.println(name + ",吃了第" + pot.pop() + "个馒头");
if ("大林".equals(name)) {
this.bigSonNum++;
} else {
this.smallSonNum++;
}
fullCake.signalAll(); // notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
}
}
//做馒头的方法
public void makeCake() {
try {
if (pot.size() >= Pot.MAX_LEN) {
System.out.println("妈妈:锅已满了,等待儿子吃馒头!");
fullCake.await(); // wait();
}
if (Pot.COUNT < 100) {
Pot.COUNT++;
pot.push(Pot.COUNT);
System.out.println("妈妈做了第" + Pot.COUNT + "个馒头");
noCake.signalAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
}
}
//显示结果
public void showResult() {
System.out.println("大林吃了:" + bigSonNum + "个馒头!");
System.out.println("小林吃了:" + smallSonNum + "个馒头!");
}
}
运行结果:
妈妈做了第1个馒头
大林,吃了第1个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第2个馒头
大林,吃了第2个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第3个馒头
小林,吃了第3个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第4个馒头
小林,吃了第4个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第5个馒头
小林,吃了第5个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第6个馒头
小林,吃了第6个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第7个馒头
小林,吃了第7个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第8个馒头
小林,吃了第8个馒头
妈妈做了第9个馒头
大林,吃了第9个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第10个馒头
大林,吃了第10个馒头
妈妈做了第11个馒头
大林,吃了第11个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第12个馒头
大林,吃了第12个馒头
妈妈做了第13个馒头
小林,吃了第13个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第14个馒头
小林,吃了第14个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第15个馒头
小林,吃了第15个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第16个馒头
小林,吃了第16个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第17个馒头
小林,吃了第17个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第18个馒头
大林,吃了第18个馒头
妈妈做了第19个馒头
大林,吃了第19个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第20个馒头
小林,吃了第20个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第21个馒头
大林,吃了第21个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第22个馒头
大林,吃了第22个馒头
妈妈做了第23个馒头
小林,吃了第23个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第24个馒头
大林,吃了第24个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第25个馒头
大林,吃了第25个馒头
妈妈做了第26个馒头
小林,吃了第26个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第27个馒头
大林,吃了第27个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第28个馒头
大林,吃了第28个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第29个馒头
大林,吃了第29个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第30个馒头
大林,吃了第30个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第31个馒头
小林,吃了第31个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第32个馒头
小林,吃了第32个馒头
妈妈做了第33个馒头
小林,吃了第33个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第34个馒头
小林,吃了第34个馒头
妈妈做了第35个馒头
大林,吃了第35个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第36个馒头
大林,吃了第36个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第37个馒头
小林,吃了第37个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第38个馒头
小林,吃了第38个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第39个馒头
大林,吃了第39个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第40个馒头
小林,吃了第40个馒头
妈妈做了第41个馒头
小林,吃了第41个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第42个馒头
小林,吃了第42个馒头
妈妈做了第43个馒头
大林,吃了第43个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第44个馒头
大林,吃了第44个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第45个馒头
大林,吃了第45个馒头
妈妈做了第46个馒头
小林,吃了第46个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第47个馒头
小林,吃了第47个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第48个馒头
小林,吃了第48个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第49个馒头
小林,吃了第49个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第50个馒头
大林,吃了第50个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第51个馒头
小林,吃了第51个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第52个馒头
小林,吃了第52个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第53个馒头
大林,吃了第53个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第54个馒头
大林,吃了第54个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第55个馒头
小林,吃了第55个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第56个馒头
大林,吃了第56个馒头
妈妈做了第57个馒头
大林,吃了第57个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第58个馒头
大林,吃了第58个馒头
妈妈做了第59个馒头
大林,吃了第59个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第60个馒头
小林,吃了第60个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第61个馒头
大林,吃了第61个馒头
妈妈做了第62个馒头
大林,吃了第62个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第63个馒头
小林,吃了第63个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第64个馒头
小林,吃了第64个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第65个馒头
大林,吃了第65个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第66个馒头
小林,吃了第66个馒头
妈妈做了第67个馒头
小林,吃了第67个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第68个馒头
大林,吃了第68个馒头
妈妈做了第69个馒头
小林,吃了第69个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第70个馒头
大林,吃了第70个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第71个馒头
大林,吃了第71个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第72个馒头
大林,吃了第72个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第73个馒头
大林,吃了第73个馒头
妈妈做了第74个馒头
大林,吃了第74个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第75个馒头
小林,吃了第75个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第76个馒头
大林,吃了第76个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第77个馒头
小林,吃了第77个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第78个馒头
大林,吃了第78个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第79个馒头
大林,吃了第79个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第80个馒头
大林,吃了第80个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第81个馒头
大林,吃了第81个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第82个馒头
大林,吃了第82个馒头
妈妈做了第83个馒头
大林,吃了第83个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第84个馒头
小林,吃了第84个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第85个馒头
小林,吃了第85个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第86个馒头
小林,吃了第86个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第87个馒头
小林,吃了第87个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第88个馒头
小林,吃了第88个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第89个馒头
大林,吃了第89个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第90个馒头
小林,吃了第90个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第91个馒头
小林,吃了第91个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第92个馒头
小林,吃了第92个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第93个馒头
大林,吃了第93个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第94个馒头
小林,吃了第94个馒头
大林锅空了,等待妈妈做馒头!
小林锅空了,等待妈妈做馒头!
妈妈做了第95个馒头
大林,吃了第95个馒头
大林锅空了,等待妈妈做馒头!
妈妈做了第96个馒头
小林,吃了第96个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第97个馒头
大林,吃了第97个馒头
小林锅空了,等待妈妈做馒头!
大林锅空了,等待妈妈做馒头!
妈妈做了第98个馒头
小林,吃了第98个馒头
妈妈做了第99个馒头
大林,吃了第99个馒头
小林锅空了,等待妈妈做馒头!
妈妈做了第100个馒头
大林,吃了第100个馒头
100个馒头做完了,妈妈线程结束!
大林吃了:51个馒头!
小林吃了:49个馒头!
上小节的使用wait/notify实现的表情输出案例,使用await/signal改写如下:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class Emotion implements Runnable {
private Lock lock;
private Condition smileCondition;
private Condition amazeCondition;
public Emotion(Lock lock) {
this.lock = lock;
smileCondition = this.lock.newCondition();
amazeCondition = this.lock.newCondition();
}
@Override
public void run() {
try {
lock.lock();
if ("^_^".equals(Thread.currentThread().getName())) {
for (int i = 1; i <= 50; i++) {
System.out.println("^_^");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i % 10 == 0 && i < 50) {
amazeCondition.signalAll();
try {
smileCondition.await();
} catch (Exception e) {
e.printStackTrace();
}
}
if (i == 50) {
amazeCondition.signalAll();
}
}
} else {
for (int i = 1; i <= 50; i++) {
System.out.println("@_@");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i % 10 == 0 && i < 50) {
smileCondition.signalAll();
try {
amazeCondition.await();
} catch (Exception e) {
e.printStackTrace();
}
}
if (i == 50) {
smileCondition.signalAll();
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock(); //释放锁
}
}
}
public class EmotionDemo {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Emotion emotion = new Emotion(lock);
Thread smileThread = new Thread(emotion,"^_^");
Thread amazeThread = new Thread(emotion,"@_@");
smileThread.start();
amazeThread.start();
}
}
运行结果:
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
@_@
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
^_^
注意:lock.lock()与lock.unlock()一定是成对出现,并且通常包裹在循环结构的最外层。 上例的另外一种实现方式如下:
package synchronizeddemo.emotion;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class SmileEmotion implements Runnable {
private Emotion emotion;
public SmileEmotion(Emotion emotion) {
this.emotion = emotion;
}
@Override
public void run() {
int count = 0;
try {
emotion.lock.lock();
while (true) {
count++;
System.out.println("^_^");
if (count % 10 == 0 && count < 50) {
emotion.amazeMotion.signalAll();
emotion.smileMotion.await();
}
if (count == 50) {
emotion.amazeMotion.signalAll();
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
emotion.lock.unlock();
}
}
}
class AmazeEmotion implements Runnable {
private Emotion emotion;
public AmazeEmotion(Emotion emotion) {
this.emotion = emotion;
}
@Override
public void run() {
int count = 0;
emotion.lock.lock();
try {
while (true) {
count++;
System.out.println("@_@");
if (count % 10 == 0 && count < 50) {
emotion.smileMotion.signalAll();
emotion.amazeMotion.await();
}
if (count == 50) {
emotion.smileMotion.signalAll();
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
emotion.lock.unlock();
}
}
}
class Emotion {
public Lock lock = new ReentrantLock();
public Condition smileMotion = lock.newCondition();
public Condition amazeMotion = lock.newCondition();
}
public class EmotionDemo {
public static void main(String[] args) {
Emotion emotion = new Emotion();
SmileEmotion smileEmotion = new SmileEmotion(emotion);
AmazeEmotion amazeEmotion = new AmazeEmotion(emotion);
Thread smileThread = new Thread(smileEmotion);
Thread amazeThread = new Thread(amazeEmotion);
smileThread.start();
amazeThread.start();
}
}