多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间的一个变量的使用或者操作。 就是多个线程在操作同一份数据时,避免对同一共享变量的争夺。 于是,引入了等待唤醒机制:
wait()、notify()
要确保调用wait()方法的时候拥有锁,所以wait()方法必须放在synchronized方法或者synchronized代码块中
生产者-消费者模型
面包类(包含生产方法和消费方法)
package thredmessage; /** * 面包类 * * @author zhou-di-an * * 2019年10月31日 */ public class Breads { // 面包类的id private int bid; // 面包的个数 private int num; // 生产面包的方法 public synchronized void product() { // 当面包的数量不为0时,该方法处于等待状态 if (0 != num) { try { wait();// 等待 } catch (InterruptedException e) { e.printStackTrace(); } } // 当面包数量为0时,那么就开始生产面包 num++; // 数量加1 bid++; // id加1 String threadname = Thread.currentThread().getName(); System.out.println(threadname + "生产了一个编号为" + bid + "的面包!"); notify(); // 当执行完后,去唤醒其他处于等待的线程 } // 消费面包的方法 public synchronized void consume() { // 当面包数量为0时,该方法处于等待状态 if (num == 0) { try { wait(); // 等待 } catch (InterruptedException e) { e.printStackTrace(); } } // 消费完面包了,所有面包的数量降为0 num--; // 数量减1 String namea1 = Thread.currentThread().getName(); System.out.println(namea1 + "买了一个编号为" + bid + "的面包"); notify(); // 当执行完后,去唤醒其他处于等待的线程 } // get和set public int getBid() { return bid; } public void setBid(int bid) { this.bid = bid; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } // 构造 public Breads(int bid, int num) { super(); this.bid = bid; this.num = num; } public Breads() { super(); } }生产面包的类
package thredmessage; /** * 线程通信--生产类 * * @author zhou-di-an * * 2019年10月31日 */ public class Producer extends Thread { // 获得面包的类 private Breads breads; // 无参构造 public Producer() { super(); } // 有参构造 public Producer(Breads breads) { super(); this.breads = breads; } public Breads getBreads() { return breads; } public void setBreads(Breads breads) { this.breads = breads; } @Override public void run() { pro(); } // 生产面包 private void pro() { // 20个 for (int i = 0; i < 10; i++) { try { // 为了明显看到效果,睡0.3秒 Thread.currentThread().sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } // 调用面包类的生产面包的方法 breads.product(); } } }消费面包的类
package thredmessage; /** * 线程通信--消费者类 * * @author zhou-di-an * * 2019年10月31日 */ public class Consume extends Thread { // 获得面包的类 private Breads breads; public Breads getBreads() { return breads; } public void setBreads(Breads breads) { this.breads = breads; } public Consume(Breads breads) { super(); this.breads = breads; } public Consume() { } @Override public void run() { con(); } public void con() { // 与生产者保持一致 for (int i = 0; i < 10; i++) { try { Thread.currentThread().sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } // 消费面包 breads.consume(); } } }测试类
package thredmessage; /** * 线程通信--测试类 * * @author zhou-di-an * * 2019年10月31日 */ public class Test { public static void main(String[] args) { // new一个面包类 Breads breads = new Breads(); // new一个生产者类 Producer producer = new Producer(breads); // new一个消费者类 Consume consume = new Consume(breads); // new一个包含消费者的线程 Thread t1 = new Thread(producer, "生产者"); // new一个包含生产者类的线程 Thread t2 = new Thread(consume, "消费者"); // 启动线程 t1.start(); t2.start(); } }测试结果
生产者生产了一个编号为1的面包! 消费者买了一个编号为1的面包 生产者生产了一个编号为2的面包! 消费者买了一个编号为2的面包 生产者生产了一个编号为3的面包! 消费者买了一个编号为3的面包 生产者生产了一个编号为4的面包! 消费者买了一个编号为4的面包 生产者生产了一个编号为5的面包! 消费者买了一个编号为5的面包 生产者生产了一个编号为6的面包! 消费者买了一个编号为6的面包 生产者生产了一个编号为7的面包! 消费者买了一个编号为7的面包 生产者生产了一个编号为8的面包! 消费者买了一个编号为8的面包 生产者生产了一个编号为9的面包! 消费者买了一个编号为9的面包 生产者生产了一个编号为10的面包! 消费者买了一个编号为10的面包