简体   繁体   English

从具有多个线程的阻塞队列中读取

[英]Reading from blocking queue with multiple threads

I have a producer-consumer model using a blocking queue where 4 threads read files from a directory puts it to the blocking queue and 4 threads(consumer) reads from blocking queue.我有一个生产者-消费者 model 使用阻塞队列,其中 4 个线程从目录读取文件将其放入阻塞队列,4 个线程(消费者)从阻塞队列读取。

My problem is every time only one consumer reads from the Blockingqueue and the other 3 consumer threads are not reading:我的问题是每次只有一个消费者从 Blockingqueue 读取,而其他 3 个消费者线程没有读取:

        final BlockingQueue<byte[]> queue = new LinkedBlockingQueue<>(QUEUE_SIZE);

            CompletableFuture<Void> completableFutureProducer = produceUrls(files, queue, checker);
//not providing code for produceData , it is working file with all 4 //threads writing to Blocking queue. Here is the consumer code.

    private CompletableFuture<Validator> consumeData(
            final Response checker,
            final CompletableFuture<Void> urls
    ) {
        return CompletableFuture.supplyAsync(checker, 4)
                .whenComplete((result, err) -> {
                    if (err != null) {
                        LOG.error("consuming url worker failed!", err);
                        urls.cancel(true);
                    }
    });


    }
  completableFutureProducer.join();
            completableFutureConsumer.join();

This is my code.这是我的代码。 Can someone tell me what I am doing wrong?有人可以告诉我我做错了什么吗? Or help with correct code.或帮助提供正确的代码。 Why is one consumer reading from the Blocking queue.为什么一位消费者从阻塞队列中读取数据。

Adding code for Response class reading from Blocking queue:为从阻塞队列读取的响应 class 添加代码:

    @Slf4j
    public final class Response implements Supplier<Check> {
        private final BlockingQueue<byte[]> data;
        private final AtomicBoolean producersComplete;
        private final Calendar calendar = Calendar.getInstance();
    
        public ResponseCode(
                final BlockingQueue<byte[]> data
        ) {
            this.data = data;
            producersDone = new AtomicBoolean();
    
        }
public void notifyProducersDone() {
    producersComplete.set(true);
}

        @Override
        public Check get() {
            try {
                Check check = null;
                try {
                    while (!data.isEmpty() || !producersDone.get()) {
                        final byte[] item = data.poll(1, TimeUnit.SECONDS);
                        if (item != null) {
                           LOG.info("{}",new String(item));
// I see only one thread printing result here .
                            validator = validateData(item);
                        }
                    }
        
                } catch (InterruptedException | IOException e) {
                    Thread.currentThread().interrupt();
                    throw new WriteException("Exception occurred while data validation", e);
        
                } 
                return check;
            } finally {
                LOG.info("Done reading data from BlockingQueue");
            }
        }
    }

It's hard to diagnose from this alone, but it's probably not correct to check for data.isEmpty() because the queue may happen to be temporarily empty (but later get items).仅凭这一点很难诊断,但检查data.isEmpty()可能不正确,因为队列可能碰巧暂时为空(但稍后会获取项目)。 So your threads might exit as soon as they encounter a temporarily empty queue.因此,您的线程可能会在遇到临时空队列时立即退出。

Instead, you can exit if producers were done AND you got an empty result from the poll .相反,如果生产者完成并且您从poll中得到一个空结果,您可以退出。 That way the threads only exit when there are truly no more items to process.这样,只有在确实没有更多项目要处理时,线程才会退出。

It's a bit odd though that you are returning the result of the last item (alone).尽管您正在返回最后一项(单独)的结果,但这有点奇怪。 Are you sure this is what you want?你确定这是你想要的吗?

EDIT: I've done something very similar recently.编辑:我最近做了一些非常相似的事情。 Here is a class that reads from a file, transforms the lines in a multi-threaded way, then writes to a different file (the order of lines are preserved). 是一个 class 从文件读取,以多线程方式转换行,然后写入不同的文件(保留行的顺序)。
It also uses a BlockingQueue .它还使用BlockingQueue It's very similar to your code, but it doesn't check for quue.isEmpty() for the aforementioned reason.它与您的代码非常相似,但由于上述原因,它不检查quue.isEmpty() It works fine for me.这对我来说可以。

4+4 threads is not that many, so you better do not use asynchronous tools like CompletableFuture. 4+4线程并没有那么多,所以你最好不要使用CompletableFuture之类的异步工具。 Simple multithreaded program would be simpler and work faster.简单的多线程程序会更简单,工作更快。

Having

 BlockingQueue<byte[]> data;

don't use data.poll() ;不要使用data.poll()

use data.take();使用data.take();

When you have lets say 1 item in the queue, and 4 consumers, one of them will poll the item rendering queue to be empty.当您说队列中有 1 个项目和 4 个消费者时,其中一个将轮询项目呈现队列为空。 Then 3 of the rest of the consumers checks if queue.isEmpty() , and since it is - quits the loop.然后消费者的 rest 中的 3 个检查是否queue.isEmpty() ,并且因为它是 - 退出循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM