实例
package demo3;
import java.util.ArrayList;
import java.util.List;
/**
* 线程与线程协作(通信),生产者/消费者
* 生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。
* (关键)该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
* 要解决该问题:
* 就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。
* 同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者,通常采用线程间通信的方法解决该问题。
*
* 定义一个盘子类,可以放鸡蛋和取鸡蛋
* 盘子里只能放一个鸡蛋,A线程专门往盘子里放鸡蛋,如果盘子里有鸡蛋,则一直等到盘子里没鸡蛋,
* B线程专门从盘子里取鸡蛋,如果盘子里没鸡蛋,则一直等到盘子里有鸡蛋。
*
*/
public class Plate {
/** 装鸡蛋的盘子 */
List<Object> eggs = new ArrayList<Object>();
/**
* 取鸡蛋
*/
public synchronized Object getEgg() {
//如果盘子为空、线程进入阻塞
while (eggs.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Object egg = eggs.get(0);
eggs.clear();// 清空盘子
//盘子不为空(执行线程),唤醒阻塞队列的某线程到就绪队列
notify();
System.out.println("拿到鸡蛋");
return egg;
}
/**
* 放鸡蛋
*/
public synchronized void putEgg(Object egg) {
//判断盘子是否为空,放入一个鸡蛋,
while (eggs.size() > 0) {
try {
wait();//盘子非空,执行等待,这个A线程进入阻塞队列(在wait方法说明中,也推荐使用while)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
eggs.add(egg);// 往盘子里放鸡蛋
//假设CPU又调度了一个A线程
notify();// 唤醒阻塞队列的某线程到就绪队列
System.out.println("放入鸡蛋");
}
/**
* 放鸡蛋线程
*/
static class AddThread implements Runnable {
private Plate plate;
private Object egg = new Object();
public AddThread(Plate plate) {
this.plate = plate;
}
public void run() {
plate.putEgg(egg);
}
}
/**
* 取鸡蛋线程
*/
static class GetThread implements Runnable {
private Plate plate;
public GetThread(Plate plate) {
this.plate = plate;
}
public void run() {
plate.getEgg();
}
}
public static void main(String args[]) {
Plate plate = new Plate();
for(int i = 0; i < 10; i++) {
new Thread(new AddThread(plate)).start();
new Thread(new GetThread(plate)).start();
}
}
}
运行结果
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
放入鸡蛋
拿到鸡蛋
Process finished with exit code 0
网友评论