问题:一个仓库最多容纳6个产品,制造商现在要制造20件产品存入仓库,消费者要从仓库取出20件产品来消费,制造商生产产品和消费者消费产品的速度很可能不一样!
/**
* 定义仓库
* @author Liao
*/
class SyncStack{
/*用数组来表示仓库的容量*/
char[] data = new char[6];
/*定义数组下标的标示*/
int cnt = 0;
/**
* 把生产出来的产品放入仓库中
* 这里使用线程同步的关键字synchronized
* 执行push()方法的时候就不能执行pop()操作!!!!
* @param ch 模拟产品的字符
*/
public synchronized void push(char ch){
/*如果仓库已满*/
while (cnt == data.length){//这是一个while,也就是说如果为true的话,将会一直执行
/*如果仓库满了的话,我们就使得生产线程进入等待状态【注:这里不能通过sleep()来控制哈,谁知道消费者啥时候来取,谁知道睡多长时间呢?所以要使用wait()进行等待】*/
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
/*通知正在等待的线程进入就绪状态(可能不会立即执行),即使没有线程在等待也不会报错,所以一定要加上这句,否则正在等待的线程可能会陷入阻塞*/
this.notify();
/*把产品出入仓库*/
data[cnt] = ch;
/*数组下标加一*/
cnt ++;
System.out.printf("生产了: %c\n", ch);
System.out.printf("容器中现在共有%d个字符!\n\n", cnt);
}
/**
* 消费者从仓库中取出产品
* 这里也要使用线程同步
* 执行pop()方法的时候就不能执行push()方法
* @throws
*/
public synchronized char pop() {
char ch;
/*如果仓库中没有产品*/
while (cnt == 0){
/*如果仓库中没有产品,我们就让消费线程进入等待状态*/
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
/*通知正在等待的线程进入就绪状态(可能不会立即执行),即使没有线程在等待也是不会报错的,所以一定要加上这句,否则正在等待的线程可能会陷入阻塞*/
this.notify();
/*取出最上面的产品*/
ch = data[cnt - 1];
/*数组的下标要减去1*/
cnt --;
System.out.printf("取出: %c\n", ch);
System.out.printf("容器中现在共有%d个字符!\n\n", cnt);
return ch;
}
}
/**
* 定义生产者
* @author Liao
*/
class Producer implements Runnable{
/*定义仓库【生产者生产处产品就把产品放入仓库中】*/
public SyncStack s = null;
/*构造函数,把仓库传进来*/
public Producer(SyncStack s) {
this.s = s;
}
/**
* 生产操作
*/
public void run() {
char ch;
/*生产20个产品*/
for (int i=0; i<20; i++){
/*一个字符模拟一个产品*/
ch = (char) ('a' + i);
/*把制造出来的产品放入仓库中*/
s.push(ch);
}
}
}
/**
* 定义消费者
* @author Liao
*/
class Consumer implements Runnable{
/*定义仓库【消费者从仓库中取出产品】*/
public SyncStack s = null;
/*构造函数*/
public Consumer(SyncStack s) {
this.s = s;
}
/*消费者消费产品*/
public void run() {
/*遍历消费20个产品*/
for (int i=0; i<20; i++){
/*从仓库中取出一个产品*/
s.pop();
/*每隔500ms取出一个产品*/
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 测试类
* @author Liao
*
*/
public class ProducerConsumerTest {
public static void main(String[] args) {
/*创建仓库*/
SyncStack ss = new SyncStack();
/*创建生产者*/
Producer producer = new Producer(ss);
/*创建消费者*/
Consumer consumer = new Consumer(ss);
/*创建生产者线程*/
Thread pThread = new Thread(producer);
/*创建消费者线程*/
Thread cThread = new Thread(consumer);
/*启动两个线程*/
pThread.start();
cThread.start();
}
}
总结:
1:a.wait():将执行a.wait()的线程进入阻塞状态,让出CPU的控制权,释放对a的锁定。
2:a.notify():叫醒正在等待的线程,使其进入就绪状态,需要注意的是,此时即使没有线程在等待,调用这个方法也是不会出错的。
3:a.notifyAll():叫醒其他所有因为执行了wait()而陷入阻塞的线程。
4:不能使用sleep(XXX),和设置优先级来控制哪一个线程先执行,因为这些都不能是线程立即进入运行状态,而是进入就绪状态。
注:notify()和notifyAll()不是叫醒调用他们的当前线程,而是叫醒其他因为调用wait()而陷入阻塞的线程。