簡體   English   中英

消費者無法使用Java中的簡單生產者/消費者/隊列代碼工作

[英]Consumer doesn't work in my simple producer/consumer/queue code in Java

我試圖在Java 11中實現一個簡單的生產者/消費者系統。基本上,我每個人都有兩個線程,外加一個全局隊列,如下所示:

  • 全局優先級隊列。
  • 生產者的第一個線程運行HTTP服務器,偵聽傳入的HTTP消息,並在收到消息后將其作為作業pushes送到隊列( queue.size遞增)
  • 第二個線程,消費者,不斷地peeks隊列。 如果存在一個作業( job ! = null ),則在某個位置提交HTTP請求,並在成功接收后從隊列中輪詢該請求( queue.size()遞減)。

骨架如下:

主類:

public class Manager
{
    private Consumer consumer;
    private Producer producer;
    Queue queue;

    public static void main (String args[])
    {
        consumer = new Consumer();
        producer = new Producer();
    }
} 

生產者類別:

public class Producer implements Runnable
{
    public Producer()
    {
        Thread producer = new Thread(this);
        producer.start();
    }

    public void run()
    {
            //HTTP server starts, listens, and adds to the queue upon receiving a Job
            server.start();
            Manager.queue.add(new Job());
    }
}

消費類:

public class Consumer implements Runnable
{
    public Consumer()
    {
        Thread consumer = new Thread(this);
        consumer.start();
    }

    public void run()
    {
    // Thread.sleep(1);

        while(true)
        {
            //get an object off the queue
            Job job= Manager.queue.peek();
            //do some stuff with the object
        }
    }
}

Producerqueue 但是問題出在Consumer 上面的Consumer代碼(帶有while(true)循環)不會窺視該項目。 但是,當我在while(true)循環之前添加Thread.sleep(x) while(true) ,即使x=1 ms ,它也可以正常工作,並且成功地捕獲了該項。

問題是什么? 從理論上講, while(true)循環應該不是問題! 為什么看不到並peek物品?

問題的原因:隊列之間的讀寫操作不同步。

在這里發生的是,兩個線程都在不同的CPU內核上運行,並使用它們自己的隊列副本,因此生產者可能正在添加內容,而且這些更改甚至可能傳播到RAM中,但是使用者從未檢查過RAM中的任何內容,因為它擁有該隊列的緩存副本,所以女巫保持為空。

Thread.sleep()起作用了,因為在喚醒時,線程必須從RAM那里獲取所有可能的內容。

正確的方法是僅在同步隊列時訪問隊列,如下所示:

在生產者中:

synchronized(Manager.queue) {
     Manager.queue.add(new Job());
}

在消費者中:

boolean continue = true;
while (continue) {
    synchronized(Manager.queue) {
        Job job=Manager.queue.pop();
    }
}

最后一點: while (true)效率極低,您可以使用Object.wait()Object.notify()

在生產者中:

synchronized(Manager.queue) {
     Manager.queue.add(new Job());
     Manager.queue.notify();
}

在消費者中:

boolean continue = true;
while (continue) {
    synchronized(Manager.queue) {
        while (Manager.queue.peek() == null) {
            Manager.queue.wait();
        }
        Job job=Manager.queue.pop();
    }
}

PriorityQueue 不是線程安全的,而PriorityBlockingQueue 只要您不使用BlockingQueue接口中定義的任何方法,這兩種實現都是可以互換的。 簡單地改變PriorityQueuePriorityBlockingQueue應該解決您的問題。

暫無
暫無

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

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