线程通信:等待、唤醒
Object方法 | 这些方法在拥有资源时才能调用 |
---|---|
notify | 唤醒某个线程。唤醒后不是立马执行,而是等CPU分配 |
wait | 等待,释放锁,不占用CPU资源 |
notifyAll | 唤醒全部等待的线程 |
重点:资源的有效利用
生产一个,消费一个;再生产一个,再消费一个
以热干面为例(生产者消费者问题):
class 热干面 { int isOK = 0;}class 生产者 implements Runnable { 热干面 m; public 生产者(热干面 m) { this.m = m; } public void 做面() { try { synchronized (m) { if (m.isOK > Desk.BUFFER_MAX) { System.out.println("+等需要做了再做"); m.wait(); System.out.println("+开始做"); } m.isOK++; System.out.println("+做面" + m.isOK); m.notify(); } } catch (Exception e) { e.printStackTrace(); } } public void run() { while (true) { try { Thread.sleep(Desk.做面时间); } catch (InterruptedException e) { e.printStackTrace(); } 做面(); // 生产面 } }}class 消费者 implements Runnable { 热干面 m; public 消费者(热干面 m) { this.m = m; } public void 吃面() { try { synchronized (m) {// # 锁住面对象 if (m.isOK <= 0) { System.out.println("------等面"); m.wait();// 等待,释放锁 System.out.println("------有面了"); } System.out.println("------吃面:" + m.isOK); m.isOK--; m.notify();// 唤醒另一个线程,但是,俩线程等CPU执行权 } } catch (Exception e) { e.printStackTrace(); } } public void run() { while (true) { try { Thread.sleep(Desk.吃面时间); } catch (InterruptedException e) { e.printStackTrace(); } 吃面(); } }}class Desk {// 为了管理对象、模拟现实场景,可以不要 public static final int 做面时间 = 100; public static final int 吃面时间 = 100; public static final int BUFFER_MAX = 1; 热干面 msg = new 热干面(); 生产者 m = new 生产者(msg); 消费者 c = new 消费者(msg); Thread t1 = new Thread(m); // 生产者线程 Thread t2 = new Thread(c); // 消费者线程 public void fn() { t1.start(); t2.start(); }}public class 生产者消费者问题 { public static void main(String[] args) { Desk d = new Desk(); d.fn(); }}