Java lambdas LinkedBlockingQueue意外行为

时间:2016-10-23 12:57:53

标签: java multithreading lambda blockingqueue

我正在尝试从使用lambda创建的线程添加t linkedBlockingQueue中的元素,当我使用take方法轮询队列时,我可以看到从线程输入的最后一个值会覆盖以前的值。

以下是代码: -

public List<EntryBarricade> entryBarricades() {
    List<EntryBarricade> entryBarricades = new ArrayList<>();
    EntryBarricade entryBarricade;
    Runnable runnable;

    for (int i =0;i<=1;i++) {
        EntryRequest entryRequest =  new EntryRequest("Barricade-"+i);
        runnable = new Runnable() {
            @Override
            public void run() {
                ExecutorService entryGate1 = Executors.newSingleThreadExecutor();
                for (int j =0;j<=1;j++) {
                    entryGate1.submit(() -> {
                        entryRequest.setVehicleId(Thread.currentThread().getName()
                                + " " + new Double(Math.random()));
                        entryRequestQueuingService.Queue(entryRequest);
                    });
                }
            }
        };
        entryBarricade = new EntryBarricade("Barricade-"+i, runnable);
        entryBarricades.add(entryBarricade);
    }
    return entryBarricades;
}

在轮询队列后,我得到以下内容: -

请求{barricadeId ='Barricade-0',vehicleId ='pool-2-thread-1 0.9091480024731418'} 请求{barricadeId ='Barricade-0',vehicleId ='pool-2-thread-1 0.05687657229049259'} 请求{barricadeId ='Barricade-1',vehicleId ='pool-3-thread-1 0.7978996055410615'} 请求{barricadeId ='Barricade-1',vehicleId ='pool-3-thread-1 0.2734508504023724'}

请求{barricadeId ='Barricade-0',vehicleId ='pool-2-thread-1 0.05687657229049259'} 请求{barricadeId ='Barricade-0',vehicleId ='pool-2-thread-1 0.05687657229049259'} 请求{barricadeId ='Barricade-1',vehicleId ='pool-3-thread-1 0.2734508504023724'} 请求{barricadeId ='Barricade-1',vehicleId ='pool-3-thread-1 0.2734508504023724'}

我不确定发生了什么。 有人可以解释一下这种行为吗?

谢谢,

阿玛尔

1 个答案:

答案 0 :(得分:1)

我在这里假设问题:你的entryRequest是在循环的每次迭代中创建的(在主线程中)。因此,当线程池执行程序来调用你的lamdba时,它可能已经改变了。你有绝对无法控制谁在这个变量时访问。

不是构造一个匿名的Runnable类,而是更好地编写自己的Runnable实现,将entryRequest作为参数传递给它(例如通过构造函数或setter),然后让run方法对这个传递的变量进行操作。这可确保每个线程在其自己的entryRequest实例上运行。