一些人吃馒头,一些人拿馒头。抽象出来的对象:吃馒头的人,生产馒头的人,馒头,操作过程类。
//模拟死锁。
public class ProducerConsumer
{
public static void main(String[] args)
{
//执行这个过程。
SyncStack ss = new SyncStack();
//两个线程访问的是同一个篮子。
Producer p = new Producer(ss);
Consumer c = new Consumer(ss);
new Thread(p).start();
new Thread(c).start();
}
}
class WoTou
{
int id;
WoTou(int id)
{ this.id = id;}
//重写窝头的toString方法为了后面的打印。
public String toString()
{
return "wotou: " + id;
}
}
//用栈来描述篮子。
class SyncStack
{
//撞到第几个了。
int index = 0;
//装上六个。篮子最多装六个,如果篮子满了怎么办?
WoTou[] arrWT = new WoTou[6];
//往篮子里装窝头。
public synchronized void push(WoTou wt)
{ //如果当index还未来得及加的时候,就又仍入一个馒头。
//解决问题的办法就是在执行两句的时候不能被打断。所以我们加上做锁了。
//如果篮子满了怎么办?我们就让它休息了。
while(index == arrWT.length)
{ //当前的对象wait()当前的正在对象访问的线程wait()
try{
this.wait();
} catch(InterruptedException e)
{
e.printStackTrace();
}
//和wait()对应。叫醒一个正在wait的线程。
}
this.notify();
arrWT[index] = wt;
index ++;
}
//为了在执行这个方法的时候不被打断出现的问题。
public synchronized WoTou pop()
{
//如果篮子已经是空的的了,没有馒头了,也需要等待。
while(index == 0)
{
//也让当前的线程wait()
try{
this.wait();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
//叫醒当前对象的另一个线程。
this.notify();
index--;
return arrWT[index];
}
//会出现问题,wait()之后会死过去,这个锁不会归这个对象所有,wait()和sleep()的区别。
}
// 大师傅,在生产窝头。
class Producer implements Runnable
{
//放入那个篮子中。
SyncStack ss = null;
//构造方法来告诉我使用哪个篮子。
Producer(SyncStack ss)
{
this.ss = ss;
}
//生产馒头了。
public void run()
{
for(int i=0;i<20;i++)
{
WoTou wt = new WoTou(i);
//调用篮子的push方法,把馒头扔进去。
ss.push(wt);
//每生产一个就打印一个。
System.out.println("生产了" + wt );
//每生产一个我们就休息会儿。
ss.push(wt);
try
{
//睡眠一秒钟。
Thread.sleep((int)Math.random()*200);
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
//做一个馒头的消费类。
class Consumer implements Runnable
{
//确定在哪个篮子里消费。
SyncStack ss = null;
//构造方法来告诉我使用哪个篮子。
Consumer(SyncStack ss)
{
this.ss = ss;
}
//生产馒头了。
public void run()
{
for(int i=0;i<20;i++)
{
WoTou wt = ss.pop();
System.out.println("消费了" + wt );
//每消费一个也睡眠一秒钟。
try
{
//睡眠一秒钟。
Thread.sleep((int)Math.random()*1000);
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}