//生产者和消费者
public class ProducerConsumer {
public static void main(String[] args) {
SyncStack ss = new SyncStack();
Producer p = new Producer(ss); // 把蓝子传入
Consumers c = new Consumers(ss); // 把蓝子传入
new Thread(p).start();// 三个大师傅在生产窝头
// new Thread(p).start();
// new Thread(p).start();
new Thread(c).start();// 三个食客在吃窝头
// new Thread(c).start();
// new Thread(c).start();
}
}
// 构造窝头类
class WoTou {
int id; // 用来标示是第几个
WoTou(int id) {
this.id = id;
}
public String toString() { // 重写toString方法 返回值是String字符串+id号
return "WoTou : " + id;
}
}
// 用栈来模拟蓝子,先进的后出 生产者消费者线程对象访问同一个蓝子
class SyncStack {
int index = 0; // 指向当前窝头的向上一个元素
WoTou[] arrWT = new WoTou[6]; // 蓝子的容量 构造一个窝头类数组 数组是有固定容量的
public synchronized void push(WoTou wt) { // 放窝头的方法,传进去一个窝头对象 不能被打断,所以加同步 一个生产者在生产的时候,其他生产者就不能生产了,但是可以消费
while(index == arrWT.length) { // 写while,防止被Interrupted之后执行后面的语句.即使被打断了,还要进入循环判断是否已经满了
try {
this.wait(); // 阻塞线程,index不在增加了.this.wait方法,让当前访问该对象的线程等待 阻塞住 只有锁定的对象才有资格wait.wait的过程中锁就不在归当前对象所有了.而sleep不同.睡着了也要抱着锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();// 叫醒其他正在当前对象上wait的线程对象.哪个线程在这儿等呢,就叫醒哪个线程.叫醒wait中的消费者,可以消费了.这个方法写在while(index == arrWT.length){}外面是说生产了一个就通知消费者可以吃了.如果是写在里面,则是生产到了6个才通知消费者
arrWT[index] = wt; // 把传进入的窝头对象赋给窝头类数组存放
index ++; // 放进去一个窝头.栈顶指针加1
}
public synchronized WoTou pop() { // 出窝头方法,返回值是窝头对象 不能被打断,所以加同步 一个消费者在消费的时候,其他消费者就不能消费了.但是可以生产
while(index == 0) { // 当蓝子空了
try {
this.wait(); // 需要被叫醒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notifyAll();// 叫醒wait中的生产者,可以继续生产了.已经吃了一个了
index--; // 拿出去了.窝头减1
return arrWT[index]; // 拿到窝头,返回去.拿到刚才放进去的.因为是栈
}
}
// 生产者线程 因为有很多个大师傅在生产窝头
class Producer implements Runnable {
SyncStack ss = null; // 需要知道往哪个蓝子里扔东西.所以拥有这个蓝子的一个引用
Producer(SyncStack ss) { // 构造方法,往哪个蓝子里放窝头
this.ss = ss;
}
public void run() {
for(int i=0; i<20; i++) { // 每个大师傅生产20个窝头
WoTou wt = new WoTou(i); // 构造方法里把i的值传进去,第几个窝头
ss.push(wt);
System.out.println("生产了:" + wt);
try {
Thread.sleep((int)(Math.random() * 50)); // 随机时间睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 消费者线程 有很多个食客在吃窝头
class Consumers implements Runnable {
SyncStack ss = null;
Consumers(SyncStack ss) { // 从哪个蓝子里拿窝头
this.ss = ss;
}
public void run() {
for(int i=0; i<20; i++) { // 允许每个食客吃20个窝头
WoTou wt = ss.pop(); // pop方法,返回值是窝头对象
System.out.println("消费了: " + wt);
try {
Thread.sleep((int)(Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

3767

被折叠的 条评论
为什么被折叠?



