在多线程的众多应用场景中,最为经典的线程通信是生产者与消费者模式了。此模式中生产者与消费者共享同一资源,并且互相依赖,互为条件。
应用场景
- 假设仓库只能存放一件商品,生产者将生产出来的商品放入仓库,消费者再从仓库中取走商品去消费。
- 如果仓库中已经存在商品,则生产者停止生产,直到消费者消费完商品,
- 如果仓库中无商品,则消费者停止消费,直到生产者生产出商品。
模式分析
- 对于生产者,没有生产商品之前,要通知消费者等待,生产商品之后,要通知消费者消费。
- 对于消费者,在消费商品之后,需要通知生产者生产新的商品以供自己消费。
- 在生产者与消费者模式中,仅仅有synchronized是无法实现线程的通信的。
使用到的方法
方法 | 功能 |
---|---|
wait() | 表示线程等待,直到通知 |
wait(long timeout) | 指定毫秒数等待 |
notify() | 唤醒处于等待状态的线程 |
notifyAll() | 唤醒全部线程 |
步骤一:编写Commodity商品类
这个类在生产者与消费者模式中为主要类,此类有以下功能:
- 定义了boolen类型的flag来决定何时让线程等待,何时唤醒线程。
- 利用关键字synchronized定义了Producer的生产商品功能,与Consumer的消费商品功能。
- 设置了线程等待机制与唤醒机制。
class Commodity{
private String title;//商品名称
private String content;//商品内容
//flag=true时,允许生产,禁止消费
//flag=false时,允许消费,禁止生产
private boolean flag=true;
public synchronized void produce(String title,String content){
if (this.flag==false){//禁止生产
try {
super.wait();//线程执行produce()需要等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (this.flag){//允许生产
this.title=title;
this.content=content;
this.flag=!this.flag;//生产结束,将信号灯设置为false,表述允许消费
try {
Thread.sleep(1000);//线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
super.notify();//唤醒线程
}
}
public synchronized void consume(){
if (this.flag){//禁止消费
try {
super.wait();//线程执行consume()需要等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (this.flag==false){//允许消费
System.out.println(this.title+"---->"+this.content);
this.flag=!this.flag;//消费结束,将信号灯设置为true,表示允许生产
super.notify();//唤醒线程
}
}
}
步骤二:编写生产者与消费者
Producer与Consumer两个类都要实现Runnable接口,并且覆写其中的run()方法。
class Producer implements Runnable{
private Commodity commodity;
public Producer(Commodity commodity){//构造方法
this.commodity=commodity;
}
@Override
public void run() {
for (int i = 0; i <50 ; i++) {
if (i%2==0){//生产者生产商品
this.commodity.produce("生产者","生产者正在生产");
}else {
this.commodity.produce("消费者","消费者正在消费");
}
}
}
}
class Consumer implements Runnable{
private Commodity commodity;
public Consumer(Commodity commodity){//构造方法
this.commodity=commodity;
}
@Override
public void run() {
for (int i = 0; i <50 ; i++) {
this.commodity.consume();//消费者消费商品
}
}
}
步骤三:编写测试类
public class Producer_Consumer {
public static void main(String[] args) {
Commodity commodity=new Commodity();
new Thread(new Producer(commodity)).start();//启动Producer线程
new Thread(new Consumer(commodity)).start();//启动Consumer线程
}
}
运行结果:
“生产者”,“生产者正在生产"与"消费者”,"消费者正在消费"交替出现,时间间隔为1s。