cari
Rumahhujung hadapan webtutorial js java多线程之并发协作生产者消费者设计模式

 两个线程一个生产者个一个消费者

  需求情景

  两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个

  涉及问题

  同步问题:如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用标记或加锁机制

  wait() / nofity() 方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。

  wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。

  notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。

  代码实现(共三个类和一个main方法的测试类)

  Resource.java
  /**
  * Created by yuandl on 2016-10-11./**
  * 资源
  */
  public class Resource {
  /*资源序号*/
  private int number = 0;
  /*资源标记*/
  private boolean flag = false;
  /**
  * 生产资源
  */
  public synchronized void create() {
  if (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费;
  try {
  wait();//让生产线程等待
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  number++;//生产一个
  System.out.println(Thread.currentThread().getName() + "生产者------------" + number);
  flag = true;//将资源标记为已经生产
  notify();//唤醒在等待操作资源的线程(队列)
  }
  /**
  * 消费资源
  */
  public synchronized void destroy() {
  if (!flag) {
  try {
  wait();
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  System.out.println(Thread.currentThread().getName() + "消费者****" + number);
  flag = false;
  notify();
  }
 }

  Producer.java 

  /**
  * Created by yuandl on 2016-10-11.
  *
  /**
  * 生产者
  */
  public class Producer implements Runnable {
  private Resource resource;
  public Producer(Resource resource) {
  this.resource = resource;
  }
  @Override
  public void run() {
  while (true) {
  try {
  Thread.sleep(10);
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  resource.create();
  }
  }
  }

 Consumer.java

 /**
  * 消费者
  */
  public class Consumer implements Runnable {
  private Resource resource;
  public Consumer(Resource resource) {
  this.resource = resource;
  }
  @Override
  public void run() {
  while (true) {
  try {
  Thread.sleep(10);
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  resource.destroy();
  }
  }
  }

 ProducerConsumerTest.java

  /**
  * Created by yuandl on 2016-10-11.
  */
  public class ProducerConsumerTest {
  public static void main(String args[]) {
  Resource resource = new Resource();
  new Thread(new Producer(resource)).start();//生产者线程
  new Thread(new Consumer(resource)).start();//消费者线程
  }
  }

打印结果

Thread-0生产者------------1
 Thread-1消费者****1
  Thread-0生产者------------2
  Thread-1消费者****2
  Thread-0生产者------------3
  Thread-1消费者****3
  Thread-0生产者------------4
  Thread-1消费者****4
  Thread-0生产者------------5
  Thread-1消费者****5
  Thread-0生产者------------6
  Thread-1消费者****6
  Thread-0生产者------------7
  Thread-1消费者****7
  Thread-0生产者------------8
  Thread-1消费者****8
  Thread-0生产者------------9
  Thread-1消费者****9
  Thread-0生产者------------10
  Thread-1消费者****10

以上打印结果可以看出没有任何问题


  多个线程,多个生产者和多个消费者的问题

  需求情景

  四个线程,两个个负责生产,两个个负责消费,生产者生产一个,消费者消费一个

  涉及问题

  notifyAll()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的所有线程发出可执行的通知,同时放弃锁,使自己处于等待状态。

  再次测试代码

 

 ProducerConsumerTest.java
  /**
  * Created by yuandl on 2016-10-11.
  */
  public class ProducerConsumerTest {
  public static void main(String args[]) {
  Resource resource = new Resource();
  new Thread(new Consumer(resource)).start();//生产者线程
  new Thread(new Consumer(resource)).start();//生产者线程
  new Thread(new Producer(resource)).start();//消费者线程
  new Thread(new Producer(resource)).start();//消费者线程
  }
  }

运行结果

  Thread-0生产者------------100
  Thread-3消费者****100
  Thread-0生产者------------101
  Thread-3消费者****101
  Thread-2消费者****101
  Thread-1生产者------------102
  Thread-3消费者****102
  Thread-0生产者------------103
  Thread-2消费者****103
  Thread-1生产者------------104
  Thread-3消费者****104
  Thread-1生产者------------105
  Thread-0生产者------------106
  Thread-2消费者****106
  Thread-1生产者------------107
  Thread-3消费者****107
  Thread-0生产者------------108
  Thread-2消费者****108
  Thread-0生产者------------109
  Thread-2消费者****109
  Thread-1生产者------------110
  Thread-3消费者****110

 通过以上打印结果发现问题


  101生产了一次,消费了两次

  105生产了,而没有消费

  原因分析

  当两个线程同时操作生产者生产或者消费者消费时,如果有生产者或者的两个线程都wait()时,再次notify(),由于其中一个线程已经改变了标记而另外一个线程再次往下直接执行的时候没有判断标记而导致的。

  if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。

  解决方案

  while判断标记,解决了线程获取执行权后,是否要运行!也就是每次wait()后再notify()时先再次判断标记

  代码改进(Resource中的if->while)

  Resource.java

 
 /**
  * Created by yuandl on 2016-10-11./**
  * 资源
  */
  public class Resource {
  /*资源序号*/
  private int number = 0;
  /*资源标记*/
  private boolean flag = false;
  /**
  * 生产资源
  */
  public synchronized void create() {
  while (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费;
  try {
  wait();//让生产线程等待
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  number++;//生产一个
  System.out.println(Thread.currentThread().getName() + "生产者------------" + number);
  flag = true;//将资源标记为已经生产
  notify();//唤醒在等待操作资源的线程(队列)
  }
  /**
  * 消费资源
  */
  public synchronized void destroy() {
  while (!flag) {
  try {
  wait();
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  System.out.println(Thread.currentThread().getName() + "消费者****" + number);
  flag = false;
  notify();
  }
  }

再次发现问题


  打印到某个值比如生产完74,程序运行卡死了,好像锁死了一样。

  原因分析

  notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致”死锁”。

  解决方案

  notifyAll解决了本方线程一定会唤醒对方线程的问题。

  最后代码改进(Resource中的notify()->notifyAll())

  Resource.java 

 /**
  * Created by yuandl on 2016-10-11./**
  * 资源
  */
  public class Resource {
  /*资源序号*/
  private int number = 0;
  /*资源标记*/
  private boolean flag = false;
  /**
  * 生产资源
  */
  public synchronized void create() {
  while (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费;
  try {
  wait();//让生产线程等待
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  number++;//生产一个
  System.out.println(Thread.currentThread().getName() + "生产者------------" + number);
  flag = true;//将资源标记为已经生产
  notifyAll();//唤醒在等待操作资源的线程(队列)
  }
  /**
  * 消费资源
  */
  public synchronized void destroy() {
  while (!flag) {
  try {
  wait();
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  }
  System.out.println(Thread.currentThread().getName() + "消费者****" + number);
  flag = false;
  notifyAll();
  }
  }

 运行结果

Thread-0生产者------------412
  Thread-2消费者****412
  Thread-0生产者------------413
  Thread-3消费者****413
  Thread-1生产者------------414
  Thread-2消费者****414
  Thread-1生产者------------415
  Thread-2消费者****415
  Thread-0生产者------------416
  Thread-3消费者****416
  Thread-1生产者------------417
  Thread-3消费者****417
  Thread-0生产者------------418
  Thread-2消费者****418
  Thread-0生产者------------419
  Thread-3消费者****419
  Thread-1生产者------------420
  Thread-2消费者****420

以上就大功告成了,没有任何问题


Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Evolusi JavaScript: Trend Semasa dan Prospek Masa DepanEvolusi JavaScript: Trend Semasa dan Prospek Masa DepanApr 10, 2025 am 09:33 AM

Trend terkini dalam JavaScript termasuk kebangkitan TypeScript, populariti kerangka dan perpustakaan moden, dan penerapan webassembly. Prospek masa depan meliputi sistem jenis yang lebih berkuasa, pembangunan JavaScript, pengembangan kecerdasan buatan dan pembelajaran mesin, dan potensi pengkomputeran IoT dan kelebihan.

Demystifying JavaScript: Apa yang berlaku dan mengapa pentingDemystifying JavaScript: Apa yang berlaku dan mengapa pentingApr 09, 2025 am 12:07 AM

JavaScript adalah asas kepada pembangunan web moden, dan fungsi utamanya termasuk pengaturcaraan yang didorong oleh peristiwa, penjanaan kandungan dinamik dan pengaturcaraan tak segerak. 1) Pengaturcaraan yang didorong oleh peristiwa membolehkan laman web berubah secara dinamik mengikut operasi pengguna. 2) Penjanaan kandungan dinamik membolehkan kandungan halaman diselaraskan mengikut syarat. 3) Pengaturcaraan Asynchronous memastikan bahawa antara muka pengguna tidak disekat. JavaScript digunakan secara meluas dalam interaksi web, aplikasi satu halaman dan pembangunan sisi pelayan, sangat meningkatkan fleksibiliti pengalaman pengguna dan pembangunan silang platform.

Adakah Python atau JavaScript lebih baik?Adakah Python atau JavaScript lebih baik?Apr 06, 2025 am 12:14 AM

Python lebih sesuai untuk sains data dan pembelajaran mesin, manakala JavaScript lebih sesuai untuk pembangunan front-end dan penuh. 1. Python terkenal dengan sintaks ringkas dan ekosistem perpustakaan yang kaya, dan sesuai untuk analisis data dan pembangunan web. 2. JavaScript adalah teras pembangunan front-end. Node.js menyokong pengaturcaraan sisi pelayan dan sesuai untuk pembangunan stack penuh.

Bagaimana saya memasang javascript?Bagaimana saya memasang javascript?Apr 05, 2025 am 12:16 AM

JavaScript tidak memerlukan pemasangan kerana ia sudah dibina dalam pelayar moden. Anda hanya memerlukan editor teks dan penyemak imbas untuk memulakan. 1) Dalam persekitaran penyemak imbas, jalankan dengan memasukkan fail HTML melalui tag. 2) Dalam persekitaran Node.js, selepas memuat turun dan memasang node.js, jalankan fail JavaScript melalui baris arahan.

Bagaimana cara menghantar pemberitahuan sebelum tugas bermula di kuarza?Bagaimana cara menghantar pemberitahuan sebelum tugas bermula di kuarza?Apr 04, 2025 pm 09:24 PM

Cara Menghantar Pemberitahuan Tugas di Quartz terlebih dahulu Apabila menggunakan pemasa kuarza untuk menjadualkan tugas, masa pelaksanaan tugas ditetapkan oleh ekspresi cron. Sekarang ...

Dalam JavaScript, bagaimana untuk mendapatkan parameter fungsi pada rantaian prototaip dalam pembina?Dalam JavaScript, bagaimana untuk mendapatkan parameter fungsi pada rantaian prototaip dalam pembina?Apr 04, 2025 pm 09:21 PM

Cara mendapatkan parameter fungsi pada rantaian prototaip dalam JavaScript dalam pengaturcaraan JavaScript, pemahaman dan memanipulasi parameter fungsi pada rantaian prototaip adalah tugas yang biasa dan penting ...

Apakah sebab kegagalan perpindahan gaya dinamik Vue.js dalam program WeChat Mini Webview?Apakah sebab kegagalan perpindahan gaya dinamik Vue.js dalam program WeChat Mini Webview?Apr 04, 2025 pm 09:18 PM

Analisis sebab mengapa kegagalan anjakan gaya dinamik menggunakan vue.js dalam pandangan web applet weChat menggunakan vue.js ...

Bagaimana untuk melaksanakan permintaan GET serentak untuk pelbagai pautan di Tampermonkey dan menentukan hasil pulangan dalam urutan?Bagaimana untuk melaksanakan permintaan GET serentak untuk pelbagai pautan di Tampermonkey dan menentukan hasil pulangan dalam urutan?Apr 04, 2025 pm 09:15 PM

Bagaimana untuk membuat permintaan serentak untuk pelbagai pautan dan hakim mengikut urutan untuk mengembalikan hasil? Dalam skrip Tampermonkey, kita sering perlu menggunakan pelbagai rantai ...

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Cara Membuka Segala -galanya Di Myrise
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌

Alat panas

PhpStorm versi Mac

PhpStorm versi Mac

Alat pembangunan bersepadu PHP profesional terkini (2018.2.1).

Dreamweaver Mac版

Dreamweaver Mac版

Alat pembangunan web visual

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

MantisBT

MantisBT

Mantis ialah alat pengesan kecacatan berasaskan web yang mudah digunakan yang direka untuk membantu dalam pengesanan kecacatan produk. Ia memerlukan PHP, MySQL dan pelayan web. Lihat perkhidmatan demo dan pengehosan kami.

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan