Java多线程:“基本篇”11之出产消费者问题
副标题#e#
1. 出产/消费者模子
出产/消费者问题是个很是典范的多线程问题,涉及到的工具包罗“出产者”、“消 费者”、“客栈”和“产物”。他们之间的干系如下:
(01) 出产者仅仅在仓储未满时候出产,仓满则遏制出产。
(02) 消费者仅仅在仓储有产物时候才气消费,仓空则期待。
(03) 当消费者发明仓储没产物可消费时候会通知出产者出产。
(04) 出产者在出产出可消费产物时候,应该通知期待的消费者去消费。
2. 出产/消费者实现
下面通过wait()/notify()方法实现该模子(后头在进修了线程池相关内容之后,再通过其它方法实现 出产/消费者模子)。源码如下:
// Demo1.java // 客栈 class Depot { private int capacity; // 客栈的容量 private int size; // 客栈的实际数量 public Depot(int capacity) { this.capacity = capacity; this.size = 0; } public synchronized void produce(int val) { try { // left 暗示“想要出产的数量”(有大概出产量太多,需多此出产) int left = val; while (left > 0) { // 库存已满时,期待“消费者”消费产物。 while (size >= capacity) wait(); // 获取“实际出产的数量”(即库存中新增的数量) // 假如“库存”+“想要出产的数量”>“总的容量”,则“实际增量”=“总的容量”-“当前容量”。(此时填满客栈) // 不然“实际增量”=“想要出产的数量” int inc = (size+left)>capacity ? (capacity-size) : left; size += inc; left -= inc; System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d\n", Thread.currentThread().getName(), val, left, inc, size); // 通知“消费者”可以消费了。 notifyAll(); } } catch (InterruptedException e) { } } public synchronized void consume(int val) { try { // left 暗示“客户要消费数量”(有大概消费量太大,库存不足,需多此消费) int left = val; while (left > 0) { // 库存为0时,期待“出产者”出产产物。 while (size <= 0) wait(); // 获取“实际消费的数量”(即库存中实际淘汰的数量) // 假如“库存”<“客户要消费的数量”,则“实际消费量”=“库存”; // 不然,“实际消费量”=“客户要消费的数量”。 int dec = (size<left) ? size : left; size -= dec; left -= dec; System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d\n", Thread.currentThread().getName(), val, left, dec, size); notifyAll(); } } catch (InterruptedException e) { } } public String toString() { return "capacity:"+capacity+", actual size:"+size; } } // 出产者 class Producer { private Depot depot; public Producer(Depot depot) { this.depot = depot; } // 消费产物:新建一个线程向客栈中出产产物。 public void produce(final int val) { new Thread() { public void run() { depot.produce(val); } }.start(); } } // 消费者 class Customer { private Depot depot; public Customer(Depot depot) { this.depot = depot; } // 消费产物:新建一个线程从客栈中消费产物。 public void consume(final int val) { new Thread() { public void run() { depot.consume(val); } }.start(); } } public class Demo1 { public static void main(String[] args) { Depot mDepot = new Depot(100); Producer mPro = new Producer(mDepot); Customer mCus = new Customer(mDepot); mPro.produce(60); mPro.produce(120); mCus.consume(90); mCus.consume(150); mPro.produce(110); } }
#p#副标题#e#
说明:
(01) Producer是“出产者”类,它与“客栈(depot)”关联。当挪用“出产 者”的produce()要领时,它会新建一个线程并向“客栈”中出产产物。
(02) Customer是“消费者”类,它与“客栈(depot)”关联。当挪用“消费 者”的consume()要领时,它会新建一个线程并消费“客栈”中的产物。
(03) Depot是“客栈”类,客栈中记录“客栈的容量(capacity)”以及“仓 库中当前产物数目(size)”。
#p#分页标题#e#
“客栈”类的出产要领produce()和消费要领 consume()要领都是synchronized要领,进入synchronized要领体,意味着这个线程获取到了该“仓 库”工具的同步锁。这也就是说,同一时间,出产者和消费者线程只能有一个能运行。通过同步锁 ,实现了对“残忍”的互斥会见。
对支付产要领produce()而言:当客栈满时,出产者线 程期待,需要期待消费者消费产物之后,出产线程才气出产;出产者线程出产完产物之后,会通过 notifyAll()叫醒同步锁上的所有线程,包罗“消费者线程”,即我们所说的“通知消费 者举办消费”。
对付消费要领consume()而言:当客栈为空时,消费者线程期待,需要期待出产 者出产产物之后,消费者线程才气消费;消费者线程消费完产物之后,会通过notifyAll()叫醒同步锁上 的所有线程,包罗“出产者线程”,即我们所说的“通知出产者举办出产”。
(某一次)运行功效:
Thread-0 produce( 60) --> left= 0, inc= 60, size= 60 Thread-4 produce(110) --> left= 70, inc= 40, size=100 Thread-2 consume( 90) <-- left= 0, dec= 90, size= 10 Thread-3 consume(150) <-- left=140, dec= 10, size= 0 Thread-1 produce(120) --> left= 20, inc=100, size=100 Thread-3 consume(150) <-- left= 40, dec=100, size= 0 Thread-4 produce(110) --> left= 0, inc= 70, size= 70 Thread-3 consume(150) <-- left= 0, dec= 40, size= 30 Thread-1 produce(120) --> left= 0, inc= 20, size= 50
查察本栏目