簡體   English   中英

在Java中使用wait()和notify()進行阻止

[英]Blocked using wait() and notify() in Java

我正在使用Java中的wait()notify()編寫生產者和消費者代碼。 創建Thread-0並在produce()上調用,並創建Thread-1並在consume()上調用。

public class Processor {

  private volatile List<Integer> list = new ArrayList<>();
  private final int MAX_CAPACITY = 5;
  Object lock = new Object();

  public void produce() throws InterruptedException {

    while (true) {

      while (list.size() == MAX_CAPACITY) {
        System.out.println("List is full! Producer is Waiting....");
        synchronized (lock) {
          lock.wait();
        }
      }

      synchronized (lock) {
        int random = new Random().nextInt(100);
        list.add(random);
        System.out.println("Added to list:" + random);
        lock.notify();
      }
    }
  }

  public void consume() throws InterruptedException {

    while (true) {

      while (list.size() == 0) {
        System.out.println("List is empty!! Consumer is Waiting...");
        synchronized (lock) {
          lock.wait();
        }
      }

      synchronized (lock) {
        int i = list.remove(0);
        System.out.println("Removed from list:" + i);
        lock.notify();
      }
    }
  }
}

問題是在執行期間,程序在produce()之后停止:

List is empty!! Consumer is Waiting...
Added to list:22
Added to list:45
Added to list:72
Added to list:91
Added to list:51
List is full! Producer is Waiting....

我無法理解這里的問題是什么。 我以某種方式弄清楚將while循環中的代碼包裝在produce()consume()中的synchronized塊中解決了這個問題。

produce()

synchronized (lock) {
                while (list.size() == MAX_CAPACITY) {
                    System.out.println("List is full! Producer is Waiting....");

                    lock.wait();
                }

consume

synchronized (lock) {
                while (list.size() == 0) {
                    System.out.println("List is empty!! Consumer is Waiting...");

                    lock.wait();
                }
            }

這是什么問題? 這是線程飢餓還是死鎖的情況?

編輯:調用類:

public class App {
    public static void main(String[] args) {
        final Processor processor = new Processor();

        Runnable r1 = new Runnable() {

            @Override
            public void run() {
                try {
                    processor.produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        };

        Runnable r2 = new Runnable() {

            @Override
            public void run() {
                try {
                    processor.consume();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }
        };

        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);

        t1.start();
        t2.start();


    }
}

當你執行list.size()它不是線程安全的,並且沒有保證你將看到另一個線程中的值發生了變化。 如果JIT檢測到您沒有在該線程中更改它,則它甚至可以內聯該值。

通過將synchronized塊放在循環外部,可確保值的變化可見(因為它也在while(true)循環內while(true)

使用synchronized外部循環創建讀取障礙 因此,生產者/消費者將在您檢查list.size()環路中看到最新的list 這就是為什么你移動后,它的工作原理while內循環synchronized塊。

在您的情況下,我還建議您在生產者/消費者中使用單個同步塊。

例如,在您的實現中,如果list.size() == 0對於使用者變為false ,它將釋放對lock對象的鎖定,然后在下一個語句中嘗試再次獲取鎖定以消耗數據,這是不必要且低效的。 應該是這樣的:

public void consume() throws InterruptedException {

  while (true) {
    synchronized (lock) {
      while (list.size() == 0) {
        System.out.println("List is empty!! Consumer is Waiting...");

        lock.wait();
      }

      int i = list.remove(0);
      System.out.println("Removed from list:" + i);
      lock.notify();
    }
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM