import java.util.*;
public class Consumer implements Runnable{
List<Integer> cache;
public Consumer(List<Integer> cache)
{
this.cache = cache;
}
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.notifyAll();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
import java.util.List;
import java.util.Random;
public class Producer implements Runnable {
List<Integer> cache;
public Producer(List<Integer> cache)
{
this.cache = cache;
}
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.notifyAll();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
import java.util.*;
public class Main {
public static void main(String[]args)throws Exception
{
List<Integer> cache = new ArrayList<Integer>();
new Thread(new Consumer(cache)).start();
new Thread(new Producer(cache)).start();
}
}
import java.util.*;
public class Main2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
List<Integer> cache = new ArrayList<Integer>();
new Thread(new Consumer(cache)).start();
new Thread(new Consumer(cache)).start();
new Thread(new Consumer(cache)).start();
new Thread(new Producer(cache)).start();
new Thread(new Producer(cache)).start();
new Thread(new Producer(cache)).start();
}
}
只有一个消费者和生产者的时候,等待池中只有一个线程,不会产生闭环,因而不会发生死锁
当有两个消费者c1,c2,一个生产者p1。
首先根据main中顺序,启动c1,c2,此时cache为空,c1,c2等待。
启动p1,size==0,p1获取锁并且设置cache数据,notify唤醒等待的某个线程假设为c1,c1
无法调用synchronized方法因而进入锁池,p1释放锁,继续循环获取锁并且此时size==1执行wait进入等待池
锁池中现在是c1,c1竞争到锁消费数据,假设执行notify取出c2进入锁池,因为c1已经消费过,size==0,执行wait进入等待池
c1最后也会进入等待池。所有的线程都进入等待池,程序发生死锁。
一般的synchronized导致死锁是因为不同的线程加锁时相互交叉导致互相堵塞
而wait notify导致的死锁是因为使得所有的线程同时进入等待池导致不同线程无法相互唤醒
因而我认为能依靠检测持有请求循环来检测后者的死锁,因为当所有的线程都进入某个对象的等待池,自然就会发生死锁,这时我们也能够发现死锁的原因了。