生产者-消费者
该模式在现实生活中很常见,在项目开发中也广泛应用,它是线程间通信的经典应用。 生产者是一堆线程,消费者是另一堆线程,内存缓冲区可以使用 List集合存储数据。该模式的关键之处是如何处理多线程之间的协调通信,内存缓冲区为空的时候,消费者必须等待, 而内存缓冲区满的时候,生产者必须等待,其他时候可以是个动态平衡。
下面的案例模拟实现农夫采摘水果放到筐里,小孩从筐里拿水果吃,农夫是一个线程, 小孩是一个线程,水果筐放满了,农夫停;水果筐空了,小孩停。
public class Kuang {//这个集合就是水果筐 假设最多存 10 个水果public static ArrayList<String> kuang=new ArrayList<String>();}
上述代码定义一个静态集合作为内存缓冲区用来存储数据,同时这个集合也可以作为锁去被 多个线程使用。
public class Farmer extends Thread { public void run() {while (true) {synchronized (Kuang.kuang) {//1.筐放满了就让农夫休息if (Kuang.kuang.size() == 10) {try {Kuang.kuang.wait();} catch (InterruptedException e) {}}//2.往筐里放水果Kuang.kuang.add("apple");System.out.println("农夫放了一个水果,目前筐里有" + Kuang.kuang.size()+ "个水果");//3.唤醒小孩继续吃Kuang.kuang.notify();}//4.模拟控制速度try {Thread.sleep(100);} catch (InterruptedException e) {}
上述代码就是农夫线程,不断的往集合(筐)里放水果,当筐满了就停,同时释放锁。
public class Child extends Thread { public void run() {while (true) {synchronized (Kuang.kuang) {//1.筐里没水果了就让小孩休息if (Kuang.kuang.size() == 0) {try {Kuang.kuang.wait();} catch (InterruptedException e) {}}//2.小孩吃水果Kuang.kuang.remove("apple");System.out.println("小孩吃了一个水果,目前筐里有" + Kuang.kuang.size() + "个水果");//3.唤醒农夫继续放水果Kuang.kuang.notify();}//4.模拟控制速度try {Thread.sleep(400);} catch (InterruptedException e) { e.printStackTrace();}}}}
上述代码是小孩线程,不断的从集合(筐)里拿水果吃,当筐空了就停,同时释放锁。
public class TestFarmerChild {public static void main(String[] args) { new Farmer().start();new Child().start();}}
我们创建两个线程同时运行,可以通过双方线程里的 sleep 方法模拟控制速度,当农夫往框里放水果的速度快于小孩吃水果的速度时,运行效果如下图所示:
当小孩吃水果的速度快于农夫往框里放水管的速度时,运行效果如下图所示: