生产者
public class Producer implements Runnable {
List cache;
public Producer(List<Integer> cache) {
this.cache = cache;
}
@Override
public void run() {
while (true) {
produce();
}
}
private void produce() {
synchronized (cache) {
try {
while (cache.size() == 1) {
cache.wait();
}
// 模拟一秒生产一条消息
Thread.sleep(1000);
cache.add(new Random().nextInt());
cache.notify();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
消费者
public class Consumer implements Runnable {
List cache;
public Consumer(List<Integer> cache) {
this.cache = cache;
}
@Override
public void run() {
while (true) {
consume();
}
}
private void consume() {
synchronized (cache) {
try {
while (cache.isEmpty()) {
cache.wait();
}
System.out.println("Consumer consumed [" + cache.remove(0) + "]");
cache.notify();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
运行
public class WaitNotifyTest {
public static void main(String[] args) throws Exception {
List cache = Lists.newArrayList();
new Thread(new Consumer(cache)).start();
new Thread(new Consumer(cache)).start();
new Thread(new Producer(cache)).start();
new Thread(new Producer(cache)).start();
}
}
先来说明两个定义:
锁池:假设线程A已经拥有了某个对象(不是类)的锁,而其他线程想要调用这个对象的Synchronize方法(或者Synchronize块),由于这些方法在进入Synchronize方法之前必须先或获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池
等待池:假设线程A调用了某个对象的wait方法,那么线程A就会释放该对象的锁,并且进入等待池中等待唤醒
好了场景模拟
生产者P1,P2
消费者C1,C1
第一回合
C1获得了对象锁,C2,P1,P2进入锁池,但是cache为0,C1进入等待池
Round2
C2获得了对象锁,P1,P2待在锁池中,C1待在等待池中,同理C2进入等待池
Round3
P1获得了对象锁,P2待在锁池中,C1,C2待在等待池中,P1生产一条消息,随机唤醒C1,随后又进入锁池
Round4
P1又获得了对象锁,P2,C1待在锁池中,C2待在等待池中,cache为1,P1进入等待池
Round5
P2获得了对象锁,C1待在锁池中,C2,P1待在等待池中,cache为1,P2进入等待池
round6
C1获得了对象锁,锁池暂空,C2,P1,P2待在等待池中,C1消费一条数据,随机唤醒C2,随后又进入了锁池
round7
C1又获得了对象锁,C2待在锁池中,P1,P2待在等待池中,cache为0,C1进入等待池
round8
C2获得了对象锁,cache为0,进入等待池,造成死锁
简洁版—>锁池用[]表示,等待池用()表示
[C1,c2,p1,p2]()->
c1;[c2,p1,p2]()->
c2;[p1,p2](c1)->
p1;[p2](c1,c2)->
p1;[p2,c1](c2)->
p2;[c1](p1,c2)->
c1;[c2](p1,p2)->
c2;[c1,p1](p2)->
c1;[p1](p2,c2)->
p1;[](p2,c2,c1)->
p2;[](c2,c1,p1)->
死锁
或者还有更快的GG
p1,[c1,c2,p2]()
p2,[c1,c2](p1)
c1,[c2](p1,p2)
c2,[p1](c1.p2)
p1,[](c1,c2,p2)
p2,[](c1,c2,p1)
—>死锁