Java 从BlockingQueue提取时缺少项

Java 从BlockingQueue提取时缺少项,java,multithreading,concurrency,queue,executorservice,Java,Multithreading,Concurrency,Queue,Executorservice,我有一个庞大的数据集,我需要将其填充到数据库中。我正在编写一个基于Java并发库(具有BlockingQueue和executorService的生产者-消费者模型)的代码,它可以在队列到达时不断向队列添加数据。消费者一直在检索数据,除非遇到“毒药”(然后它就死了) 主类,带有要发布的虚拟数据。有意将队列大小保持较小: public class MessageProcessor { private static final BlockingQueue<String> queue =

我有一个庞大的数据集,我需要将其填充到数据库中。我正在编写一个基于Java并发库(具有BlockingQueue和executorService的生产者-消费者模型)的代码,它可以在队列到达时不断向队列添加数据。消费者一直在检索数据,除非遇到“毒药”(然后它就死了)

主类,带有要发布的虚拟数据。有意将队列大小保持较小:

public class MessageProcessor {
private static final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(
        5, true);
private static final ExecutorService executor = Executors
        .newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private static final ExecutorService consumerExecutor = Executors
        .newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private static final String POISON = "THE_END";


public void processMessages() throws InterruptedException {

//Create and start consumer 
    Runnable consumer = new MessageConsumer(queue);
    consumerExecutor.execute(consumer);

    for (String payload : getPayload()) {
        //create and start producer with given payload
        Runnable producer = new MessageProducer(queue, payload);
        executor.execute(producer);
    }

    executor.shutdown();
    executor.awaitTermination(1, TimeUnit.MINUTES);

    consumerExecutor.shutdown();
    consumerExecutor.awaitTermination(1, TimeUnit.MINUTES);

}

private List<String> getPayload() {
    List<String> payloads = new ArrayList<>();
    payloads.add("data1");
    payloads.add("data2");
    payloads.add("data3");
    payloads.add("data4");
    payloads.add("data5");
    payloads.add("data6");
    payloads.add("data7");
    payloads.add("data8");
    payloads.add("data9");
    payloads.add("data10");
    payloads.add(POISON);

    return payloads;
}}
执行new MessageProcessor.processMessages()时,我观察到两种异常情况:

  • 消费者未能获取一个项目:data4(我假设是因为它在获取“data4”之前获取了有毒数据(“U端”))——但为什么它不从一个队列(即FIFO)中获取插入顺序的数据呢
  • 队列中的插入(put)不会按照列表中项目的顺序发生(例如,在“data3”之后插入“data7”)

  • 谢谢

    将条目放入队列是不确定的,因为您对每条消息使用唯一的runnable,而不是在单个线程中顺序循环


    正如您所说,这可能解释了为什么有些消息看不见,因为它们可能在结尾之后

    将条目放入队列是不确定的,因为您对每条消息使用唯一的runnable,而不是在单个线程中顺序循环


    正如您所说,这可能解释了为什么有些消息看不见,因为它们可能在结尾之后

    你的两个问题是一样的


    由于有多个生产者并行运行,因此不能保证第一个生产者将其元素放在第二个生产者之前的队列中。因此,这些项目在队列中没有按顺序排列,毒药出现在data4之前,因此消费者不会消费data4

    你的两个问题是一样的


    由于有多个生产者并行运行,因此不能保证第一个生产者将其元素放在第二个生产者之前的队列中。因此,这些项目在队列中没有按顺序排列,毒药出现在data4之前,因此消费者不会消费data4

    您的队列是fifo,是的,但您没有按fifo顺序将数据推送到队列中


    如果.availableProcessors()返回>1,则有多个生产者将数据推送到队列中-您的执行者管理的线程不能保证按照您调用的顺序顺序运行
    executor.execute(生产者)
    in.

    您的队列是fifo,是的,但您没有按fifo顺序将数据推送到队列中


    如果.availableProcessors()返回>1,则有多个生产者将数据推送到队列中-您的执行者管理的线程不能保证按照您调用的顺序顺序运行
    executor.execute(生产者)
    in.

    是的,对于我的特定场景,我必须在线程的父线程(一个单独的线程)中处理数据-尽管,正如你所说,这解释了上述行为..是的,对于我的特定场景,我必须在线程的父线程(一个单独的线程)中处理数据-尽管,正如你所说,这就解释了上述行为。.感谢-通过从列表中移除毒药并在生产者执行器终止后直接向队列添加毒药来修复此问题。感谢-通过从列表中移除毒药并在生产者执行器终止后直接向队列添加毒药来修复此问题。
    public class MessageProducer implements Runnable {
    private BlockingQueue<String> queue;
    private String payload;
    
    public MessageProducer(BlockingQueue<String> queue, String payload) {
        this();
        this.queue = queue;
        this.payload = payload;
    }
    
    private MessageProducer() {
    }
    
    public void run() {
        try {
                queue.put(payload);
                System.out.println("Put : " + payload );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }}
    
    public class MessageConsumer implements Runnable {
    
    private BlockingQueue<String> queue;
    private static final String POISON = "THE_END";
    
    public MessageConsumer(BlockingQueue<String> queue) {
        this();
        this.queue = queue;
    }
    
    private MessageConsumer() {
    }
    
    public void run() {
    
        String payload = "";
        do {
            try {
                payload = queue.take();
                System.out.println("Got : " + payload );
            } catch (InterruptedException ie) {
                // handle
                break;
            }
        } while (!payload.equals(POISON));
    }}
    
    Put : data1
    Put : data2
    Put : data3
    Put : data7
    Put : data6
    Put : data5
    Got : data1
    Got : data2
    Got : data3
    Got : data5
    Put : data10
    Put : data8
    Put : data9
    Got : data6
    Got : data7
    Put : data4
    Put : THE_END
    Got : data8
    Got : data9
    Got : data10
    Got : THE_END