多线程之间通信
如生产者与消费者的通信,操作同一个共享资源
关键:通过一个标记来控制资源的状态,使用wait与notify/notifyAll实现线程的切换
生产者负责生产,满则等待,空则生产;
消费者负责消费,空则等待,有则消费;
单一生产者与消费者的时候,可以使用if判断标记,使用notify唤醒对方线程
如果在多生产者多消费者的情况下,必须使用while判断标记,使用notifyAll唤醒对方线程
因为,只有使用while循环判断,才能避免多生产的问题(生产多个,只消费1个)
只有使用notifyAll才能保证对方线程被唤醒
因为notify有可能唤醒到的是本方线程,从而导致双方线程都等待,程序无法继续运行!
生产者与消费者
资源
package com.gc.thread.producer;
public class Resource{
private String name;//资源
private int No;//资源编号
boolean flag = false;//仓库是否有资源
/**
* 生产者
* @param name
*/
public synchronized void produce(String name) {
//如果已经生产了,则等待消费者消费
while(flag) {
try {
this.wait();//每次被唤醒都重新判断标记
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//为商品编号
this.name = name + (++No);
//生产1个商品
System.out.println(Thread.currentThread().getName()+"--->生产:" + this.name);
//更新标记
this.flag = true;
//唤醒消费者(如果使用notify唤醒1个线程,不能保证一定唤醒到的是对方线程,如果唤醒到了本方线程,则可能造成双方线程都处于冻结状态,程序将无法继续运行)
this.notifyAll();
}
/**
* 消费者
*/
public synchronized void consume() {
//如果没有商品,则等待生产者生产
while(!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//消费1个商品
System.out.println(Thread.currentThread().getName()+"------>消费:" + this.name);
//更新标记
this.flag = false;
//唤醒生产者
this.notifyAll();
}
}
生产者
package com.gc.thread.producer;
public class Producer implements Runnable {
private Resource r;
public Producer(Resource r) {
this.r = r;
}
@Override
public void run() {
while(true)
r.produce("goods");
}
}
消费者
package com.gc.thread.producer;
public class Consumer implements Runnable {
private Resource r;
public Consumer(Resource r) {
this.r = r;
}
@Override
public void run() {
while(true)
r.consume();
}
}
开启线程
package com.gc.thread.producer;
public class Demo {
public static void main(String[] args) {
//资源
Resource r = new Resource();
//生产者
Producer producer1 = new Producer(r);
Producer producer2 = new Producer(r);
//消费者
Consumer consumer1 = new Consumer(r);
Consumer consumer2 = new Consumer(r);
new Thread(producer1).start();
new Thread(producer2).start();
new Thread(consumer1).start();
new Thread(consumer2).start();
}
}