Amar Dev Amar Dev - 1 month ago 11
Java Question

Java lambdas LinkedBlockingQueue unexpected behaviour

I am trying to add elements in t linkedBlockingQueue from a thread, created using lambda, When I poll the queue using the take method, I can see that the last values entered from the thread overrides the previous values.

Following is the code :-

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


After polling the queue, I get the following:-

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

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

I am not sure what is happening.
Can some one please explain this behaviour ??

Thanks,

Amar

Answer

I assume the problem here: your entryRequest is created in each iteration of your loop (in the main thread). So when the thread pool executor comes to call your lamdba it might have changed already. You have absolute no control who access when this variable.

Instead of constructing an anonymous Runnable class better write your own implementation of Runnable, pass the entryRequest as parameter to it (e.g by constructor or setter) and let the run method then operate on this passed variable. This ensures that each thread operates on its own entryRequest instance.