簡體   English   中英

從具有多個線程的阻塞隊列中讀取

[英]Reading from blocking queue with multiple threads

我有一個生產者-消費者 model 使用阻塞隊列,其中 4 個線程從目錄讀取文件將其放入阻塞隊列,4 個線程(消費者)從阻塞隊列讀取。

我的問題是每次只有一個消費者從 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();

這是我的代碼。 有人可以告訴我我做錯了什么嗎? 或幫助提供正確的代碼。 為什么一位消費者從阻塞隊列中讀取數據。

為從阻塞隊列讀取的響應 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");
            }
        }
    }

僅憑這一點很難診斷,但檢查data.isEmpty()可能不正確,因為隊列可能碰巧暫時為空(但稍后會獲取項目)。 因此,您的線程可能會在遇到臨時空隊列時立即退出。

相反,如果生產者完成並且您從poll中得到一個空結果,您可以退出。 這樣,只有在確實沒有更多項目要處理時,線程才會退出。

盡管您正在返回最后一項(單獨)的結果,但這有點奇怪。 你確定這是你想要的嗎?

編輯:我最近做了一些非常相似的事情。 是一個 class 從文件讀取,以多線程方式轉換行,然后寫入不同的文件(保留行的順序)。
它還使用BlockingQueue 它與您的代碼非常相似,但由於上述原因,它不檢查quue.isEmpty() 這對我來說可以。

4+4線程並沒有那么多,所以你最好不要使用CompletableFuture之類的異步工具。 簡單的多線程程序會更簡單,工作更快。

 BlockingQueue<byte[]> data;

不要使用data.poll()

使用data.take();

當您說隊列中有 1 個項目和 4 個消費者時,其中一個將輪詢項目呈現隊列為空。 然后消費者的 rest 中的 3 個檢查是否queue.isEmpty() ,並且因為它是 - 退出循環。

暫無
暫無

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

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