消费者无法使用Java中的简单生产者/消费者/队列代码 [英] Consumer doesn't work in my simple producer/consumer/queue code in Java

查看:183
本文介绍了消费者无法使用Java中的简单生产者/消费者/队列代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试用Java 11实现一个简单的生产者/消费者系统。基本上,我为每个线程加上一个全局队列,如下所示:

I am trying to implement a simple producer/consumer system in Java 11. Basically, I take two threads for each, plus a global queue, simply as follows:


  • 全局优先级队列。

  • 第一个线程,生产者,运行HTTP服务器,侦听传入的http消息,并在收到消息后,作为一个作业推送到队列( queue.size 增量)

  • 第二个线程,消费者,持续 peeks 队列。如果有作业( job!= null ),则在某处提交HTTP请求并在成功收到后,从队列中轮询它( queue.size ()减量)。

  • A global priority queue.
  • The first thread, producer, runs a HTTP server, listens to incoming http messages, and upon receiving a message, pushes it as a job to the queue (queue.size increments)
  • The second thread, the consumer, continously peeks the queue. If there is a job (job ! = null), submits a HTTP request somewhere and upon successful receipt, polls it from the queue (queue.size() decrements).

骨架如下:

主要类别:

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
        }
    }
}

生产者队列工作 - 一切都很好。但问题出在 Consumer 。上面的消费者代码(使用而(true)循环)不会查看该项目。但是当我在之前添加 Thread.sleep(x)而while(true)循环时,即使 x = 1 ms ,它有效,并成功抓取该项目。

Producer and queue works- all good. But the problem is with the Consumer. The Consumer code above (with while(true) loop) doesn't peek the item. But when I add a Thread.sleep(x) before while(true) loop, even if x=1 ms, it works, and grabs the item successfully.

有什么问题?从理论上讲,而(true)循环应该不是问题!为什么它看不到和偷看该项目?!

What is the problem? Theoretically, while(true) loop shouldn't be a problem! Why it can not see and peek the item?!

推荐答案

问题的原因:非同步读取和写入队列。

The cause of the problem: non-synchronized reading and writing from and to a queue.

这里发生的是,在不同CPU核心上运行的两个线程都可以使用自己的队列的副本,因此生产者可能正在添加东西,这些变化甚至可能传播到RAM中,但消费者从不检查RAM中的任何内容,因为它拥有该队列自己的缓存副本,因此保持空白。

What happens here is that both threads, running on different CPU-cores work with their own copy of the queue, thus the producer might be adding stuff and these changes probably even get propagated into RAM, but the consumer never checks for anything in RAM, since it has it's own cached copy of that queue, witch stays empty.

Thread.sleep()的事情有效,因为在醒来时,线程必须从RAM中获取所有的东西,可能发生变化的地方。

The Thread.sleep() thing works, because when waking up, the thread has to get all ist stuff from RAM, where it probably changed.

正确的方法是访问队列,在进行同步时如下:

The correct way of doing it, is only accessing the Queue, when synchronized on it as follows:

在生产者中:

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

和消费者:

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

最后一点: while(true) -thing非常低效,你可以用 Object.wait()对象做一些事情.notify()

And as a final touch: the while (true)-thing is incredibly inefficient, you could do something using Object.wait() and 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();
    }
}

这篇关于消费者无法使用Java中的简单生产者/消费者/队列代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆