溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java多線程中生產(chǎn)者消費(fèi)者模型的示例分析

發(fā)布時(shí)間:2021-07-15 13:43:39 來源:億速云 閱讀:102 作者:小新 欄目:編程語言

小編給大家分享一下Java多線程中生產(chǎn)者消費(fèi)者模型的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

生產(chǎn)者消費(fèi)者模型

生產(chǎn)者:生產(chǎn)任務(wù)的個(gè)體;

消費(fèi)者:消費(fèi)任務(wù)的個(gè)體;

緩沖區(qū):是生產(chǎn)者和消費(fèi)者之間的媒介,對生產(chǎn)者和消費(fèi)者解耦。

當(dāng)

緩沖區(qū)元素為滿,生產(chǎn)者無法生產(chǎn),消費(fèi)者繼續(xù)消費(fèi);

緩沖區(qū)元素為空,消費(fèi)者無法消費(fèi),生產(chǎn)者繼續(xù)生產(chǎn);

wait()/notify()生產(chǎn)者消費(fèi)者模型

制作一個(gè)簡單的緩沖區(qū)ValueObject,value為空表示緩沖區(qū)為空,value不為空表示緩沖區(qū)滿

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

生產(chǎn)者,緩沖區(qū)滿則wait(),不再生產(chǎn),等待消費(fèi)者notify(),緩沖區(qū)為空則開始生產(chǎn)

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();
    }
  }
}

消費(fèi)者,緩沖區(qū)為空則wait(),等待生產(chǎn)者notify(),緩沖區(qū)為滿,消費(fèi)者開始消費(fèi)

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方法,啟動(dòng)一個(gè)生產(chǎn)者和一個(gè)消費(fèi)者

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();
  }
}

運(yùn)行結(jié)果如下

Set的值是:1564733938518_27520480474279
Get的值是:1564733938518_27520480474279
Set的值是:1564733938518_27520480498378
Get的值是:1564733938518_27520480498378
Set的值是:1564733938518_27520480540254
Get的值是:1564733938518_27520480540254
······

生產(chǎn)者和消費(fèi)者交替運(yùn)行,生產(chǎn)者生產(chǎn)一個(gè)字符串,緩沖區(qū)為滿,消費(fèi)者消費(fèi)一個(gè)字符串,緩沖區(qū)為空,循環(huán)往復(fù),滿足生產(chǎn)者/消費(fèi)者模型。

await()/signal()生產(chǎn)者/消費(fèi)者模型

緩沖區(qū)

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

ThreadDomain48繼承ReentrantLock,set方法生產(chǎn),get方法消費(fèi)

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() + "生產(chǎn)了value, value的當(dāng)前值是" + 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() + "消費(fèi)了value, value的當(dāng)前值是" + ValueObject.value);
      condition.signal();
    }
    catch (InterruptedException e)
    {
      e.printStackTrace();
    }
    finally
    {
      unlock();
    }
  }
}

MyThread41啟動(dòng)兩個(gè)生產(chǎn)線程和一個(gè)消費(fèi)線程

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();
  }
}

輸出結(jié)果如下

Producer1生產(chǎn)了value, value的當(dāng)前值是123
Consumer消費(fèi)了value, value的當(dāng)前值是
Producer1生產(chǎn)了value, value的當(dāng)前值是123

為什么Producer2無法生產(chǎn),消費(fèi)者無法消費(fèi)呢?是因?yàn)榇藭r(shí)緩沖區(qū)為滿,Producer1的notify()應(yīng)該喚醒Consumer卻喚醒了Producer2,導(dǎo)致Producer2因?yàn)榫彌_區(qū)為滿和Consumer沒有被喚醒而處于waiting狀態(tài),此時(shí)三個(gè)線程均在等待,出現(xiàn)了假死。

解決方案有兩種:

1.讓生產(chǎn)者喚醒所有線程,在set方法中使用condition.signalAll();

2.使用兩個(gè)Condition,生產(chǎn)者Condition和消費(fèi)者Condition,喚醒指定的線程;

正常輸入如下:

······
Producer2生產(chǎn)了value, value的當(dāng)前值是123
Consumer消費(fèi)了value, value的當(dāng)前值是
Producer2生產(chǎn)了value, value的當(dāng)前值是123
Consumer消費(fèi)了value, value的當(dāng)前值是
Producer2生產(chǎn)了value, value的當(dāng)前值是123
Consumer消費(fèi)了value, value的當(dāng)前值是
Producer1生產(chǎn)了value, value的當(dāng)前值是123
Consumer消費(fèi)了value, value的當(dāng)前值是
Producer1生產(chǎn)了value, value的當(dāng)前值是123
Consumer消費(fèi)了value, value的當(dāng)前值是
Producer1生產(chǎn)了value, value的當(dāng)前值是123
Consumer消費(fèi)了value, value的當(dāng)前值是
Producer1生產(chǎn)了value, value的當(dāng)前值是123
Consumer消費(fèi)了value, value的當(dāng)前值是
Producer1生產(chǎn)了value, value的當(dāng)前值是123
Consumer消費(fèi)了value, value的當(dāng)前值是
······

以上是“Java多線程中生產(chǎn)者消費(fèi)者模型的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI