首页 > 编程 > Java > 正文

Java多线程 生产者消费者模型实例详解

2019-11-26 08:37:12
字体:
来源:转载
供稿:网友

生产者消费者模型

生产者:生产任务的个体;

消费者:消费任务的个体;

缓冲区:是生产者和消费者之间的媒介,对生产者和消费者解耦。


缓冲区元素为满,生产者无法生产,消费者继续消费;

缓冲区元素为空,消费者无法消费,生产者继续生产;

wait()/notify()生产者消费者模型

制作一个简单的缓冲区ValueObject,value为空表示缓冲区为空,value不为空表示缓冲区满

public class ValueObject {  public static String value = "";}

生产者,缓冲区满则wait(),不再生产,等待消费者notify(),缓冲区为空则开始生产

public class Producer {  private Object lock;  public Producer(Object lock)  {    this.lock = lock;  }  public void setValue()  {    try    {      synchronized (lock)      {        if (!ValueObject.value.equals(""))          lock.wait();        String value = System.currentTimeMillis() + "_" + System.nanoTime();        System.out.println("Set的值是:" + value);        ValueObject.value = value;        lock.notify();      }    }    catch (InterruptedException e)    {      e.printStackTrace();    }  }}

消费者,缓冲区为空则wait(),等待生产者notify(),缓冲区为满,消费者开始消费

public class Customer {  private Object lock;  public Customer(Object lock)  {    this.lock = lock;  }  public void getValue()  {    try    {      synchronized (lock)      {        if (ValueObject.value.equals(""))          lock.wait();        System.out.println("Get的值是:" + ValueObject.value);        ValueObject.value = "";        lock.notify();      }    }    catch (InterruptedException e)    {      e.printStackTrace();    }  }}

main方法,启动一个生产者和一个消费者

public class Main {  public static void main(String[] args)  {    Object lock = new Object();    final Producer producer = new Producer(lock);    final Customer customer = new Customer(lock);    Runnable producerRunnable = new Runnable()    {      public void run()      {        while (true)        {          producer.setValue();        }      }    };    Runnable customerRunnable = new Runnable()    {      public void run()      {        while (true)        {          customer.getValue();        }      }    };    Thread producerThread = new Thread(producerRunnable);    Thread CustomerThread = new Thread(customerRunnable);    producerThread.start();    CustomerThread.start();  }}

运行结果如下

Set的值是:1564733938518_27520480474279Get的值是:1564733938518_27520480474279Set的值是:1564733938518_27520480498378Get的值是:1564733938518_27520480498378Set的值是:1564733938518_27520480540254Get的值是:1564733938518_27520480540254・・・・・・

生产者和消费者交替运行,生产者生产一个字符串,缓冲区为满,消费者消费一个字符串,缓冲区为空,循环往复,满足生产者/消费者模型。

await()/signal()生产者/消费者模型

缓冲区

public class ValueObject {  public static String value = "";}

ThreadDomain48继承ReentrantLock,set方法生产,get方法消费

public class ThreadDomain48 extends ReentrantLock{  private Condition condition = newCondition();  public void set()  {    try    {      lock();      while (!"".equals(ValueObject.value))        condition.await();      ValueObject.value = "123";      System.out.println(Thread.currentThread().getName() + "生产了value, value的当前值是" + ValueObject.value);      condition.signal();    }    catch (InterruptedException e)    {      e.printStackTrace();    }    finally    {      unlock();    }  }  public void get()  {    try    {      lock();      while ("".equals(ValueObject.value))        condition.await();      ValueObject.value = "";      System.out.println(Thread.currentThread().getName() + "消费了value, value的当前值是" + ValueObject.value);      condition.signal();    }    catch (InterruptedException e)    {      e.printStackTrace();    }    finally    {      unlock();    }  }}

MyThread41启动两个生产线程和一个消费线程

public class MyThread41 {  public static void main(String[] args)  {    final ThreadDomain48 td = new ThreadDomain48();    Runnable producerRunnable = new Runnable()    {      public void run()      {        for (int i = 0; i < Integer.MAX_VALUE; i++)          td.set();      }    };    Runnable customerRunnable = new Runnable()    {      public void run()      {        for (int i = 0; i < Integer.MAX_VALUE; i++)          td.get();      }    };    Thread ProducerThread1 = new Thread(producerRunnable);    ProducerThread1.setName("Producer1");    Thread ProducerThread2 = new Thread(producerRunnable);    ProducerThread2.setName("Producer2");    Thread ConsumerThread = new Thread(customerRunnable);    ConsumerThread.setName("Consumer");    ProducerThread1.start();    ProducerThread2.start();    ConsumerThread.start();  }}

输出结果如下

Producer1生产了value, value的当前值是123Consumer消费了value, value的当前值是Producer1生产了value, value的当前值是123

为什么Producer2无法生产,消费者无法消费呢?是因为此时缓冲区为满,Producer1的notify()应该唤醒Consumer却唤醒了Producer2,导致Producer2因为缓冲区为满和Consumer没有被唤醒而处于waiting状态,此时三个线程均在等待,出现了假死。

解决方案有两种:

1.让生产者唤醒所有线程,在set方法中使用condition.signalAll();

2.使用两个Condition,生产者Condition和消费者Condition,唤醒指定的线程;

正常输入如下:

・・・・・・Producer2生产了value, value的当前值是123Consumer消费了value, value的当前值是Producer2生产了value, value的当前值是123Consumer消费了value, value的当前值是Producer2生产了value, value的当前值是123Consumer消费了value, value的当前值是Producer1生产了value, value的当前值是123Consumer消费了value, value的当前值是Producer1生产了value, value的当前值是123Consumer消费了value, value的当前值是Producer1生产了value, value的当前值是123Consumer消费了value, value的当前值是Producer1生产了value, value的当前值是123Consumer消费了value, value的当前值是Producer1生产了value, value的当前值是123Consumer消费了value, value的当前值是・・・・・・

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表