[英]Consumer doesn't work in my simple producer/consumer/queue code in Java
我試圖在Java 11中實現一個簡單的生產者/消費者系統。基本上,我每個人都有兩個線程,外加一個全局隊列,如下所示:
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
}
}
}
Producer
和queue
。 但是問題出在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
接口中定義的任何方法,這兩種實現都是可以互換的。 簡單地改變PriorityQueue
到PriorityBlockingQueue
應該解決您的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.