سؤال

يرجى نسخ البرنامج أدناه ومحاولة التشغيل في IDE الخاص بك. إنه تطبيق بسيط للمنتجات - إنه يعمل بشكل جيد عندما أستخدم منتجًا واحدًا وخيط مستهلك واحد ولكنه يفشل عند استخدام 2 لكل منهما. واسمحوا لي أن أعرف السبب الذي يجعل هذا البرنامج معلقًا أو هل هناك أي شيء آخر خطأ في ذلك.

import java.util.LinkedList;
import java.util.Queue;

public class PCQueue {

 private volatile Queue<Product> productQueue = new LinkedList<Product>();

 public static void main(String[] args) {
  PCQueue pc = new PCQueue();

  Producer producer = new Producer(pc.productQueue);
  Consumer consumer = new Consumer(pc.productQueue);

  new Thread(producer, "Producer Thread 1").start();
  new Thread(consumer, "Consumer Thread 1").start();

  new Thread(producer, "Producer Thread 2").start();
  new Thread(consumer, "Consumer Thread 2").start();
 }

}

class Producer implements Runnable {

 private Queue<Product> queue = null;

 private static volatile int refSerialNumber = 0;

 public Producer(Queue<Product> queue) {
  this.queue = queue;
 }

 @Override
 public void run() {

  while (true) {
   synchronized (queue) {
    while (queue.peek() != null) {
     try {
      queue.wait();
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
    queue.add(new Product(++refSerialNumber));
    System.out.println("Produced by: "
      + Thread.currentThread().getName() + " Serial Number: "
      + refSerialNumber);

    queue.notify();
   }
  }

 }
}

class Consumer implements Runnable {

 private Queue<Product> queue = null;

 public Consumer(Queue<Product> queue) {
  this.queue = queue;
 }

 @Override
 public void run() {
  while (true) {
   synchronized (queue) {
    while (queue.peek() == null) {
     try {
      queue.wait();
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    Product product = queue.remove();
    System.out.println("Consumed by: "
      + Thread.currentThread().getName() + " Serial Number: "
      + product.getSerialNumber());

    queue.notify();

   }
  }

 }

}

class Product {
 private int serialNumber;

 public Product(int serialNumber) {
  this.serialNumber = serialNumber;
 }

 public int getSerialNumber() {
  return serialNumber;
 }
}
هل كانت مفيدة؟

المحلول

المشكلة هي أنك تستخدم قائمة الانتظار. Notify () والتي ستستيقظ فقط موضوع واحد ينتظر في قائمة الانتظار. تخيل المنتج 1 مكالمات الإخطار () وتستيقظ المنتج 2. يرى المنتج 2 أن هناك شيء ما في قائمة الانتظار حتى لا ينتج أي شيء ويعود ببساطة إلى مكالمة Wait (). الآن ينتظر كل من منتجيك والمستهلكين جميعًا إخطارهم ولا يوجد أحد يعمل لإخطار أي شخص.

لحل المشكلة في الكود الخاص بك ، استخدم Queue.NotifyAll () لإيقاظ كل مؤشر ترابط محظور عند انتظار (). سيسمح هذا للمستهلكين بالتشغيل.

كملاحظة ، يحد تطبيقك من قائمة الانتظار إلى وجود عنصر واحد على الأكثر. لذلك لن ترى أي فائدة من المجموعة الثانية من المنتجين والمستهلكين. لأفضل في كل مكان في التنفيذ ، أقترح عليك أن تنظر إلى blockingqueue واستخدام تطبيق يمكن أن يكون محدودًا ، على سبيل المثال ، arrayblockingqueue. بدلاً من مزامنة واستخدام الانتظار/الإخطار ، ما عليك سوى الاستخدام blockingqueue.offer () و blockingqueue.take ().

نصائح أخرى

بدلاً من queue.notify () استخدم queue.notifyall ()

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top