Let's assume that we have the following Order class:
public class Order {
private final int customerId;
public Order(int customerId) {
this.customerId = customerId;
}
// getter and toString() omitted for brevity
}
And, we write CustomerOrder as follows:
public class CustomerOrder implements Runnable {
private static final Logger logger
= Logger.getLogger(CustomerOrder.class.getName());
private static final Random rnd = new Random();
private static final ThreadLocal<Order>
customerOrder = new ThreadLocal<>();
private final int customerId;
public CustomerOrder(int customerId) {
this.customerId = customerId;
}
@Override
public void run() {
logger.info(() -> "Given customer id: " + customerId
+ " | " + customerOrder.get()
+ " | " + Thread.currentThread().getName());
customerOrder.set(new Order(customerId));
try {
Thread.sleep(rnd.nextInt(2000));
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
logger.severe(() -> "Exception: " + ex);
}
logger.info(() -> "Given customer id: " + customerId
+ " | " + customerOrder.get()
+ " | " + Thread.currentThread().getName());
customerOrder.remove();
}
}
For each customerId, we have a dedicated thread that we control:
CustomerOrder co1 = new CustomerOrder(1);
CustomerOrder co2 = new CustomerOrder(2);
CustomerOrder co3 = new CustomerOrder(3);
new Thread(co1).start();
new Thread(co2).start();
new Thread(co3).start();
So, each thread modifies a certain instance of CustomerOrder (there is a particular thread for each instance).
The run() method fetches the order for the given customerId and stores it in the ThreadLocal variable, using the set() method.
A possible output will be as follows:
[14:48:20] [INFO]
Given customer id: 3 | null | Thread-2
[14:48:20] [INFO]
Given customer id: 2 | null | Thread-1
[14:48:20] [INFO]
Given customer id: 1 | null | Thread-0
[14:48:20] [INFO]
Given customer id: 2 | Order{customerId=2} | Thread-1
[14:48:21] [INFO]
Given customer id: 3 | Order{customerId=3} | Thread-2
[14:48:21] [INFO]
Given customer id: 1 | Order{customerId=1} | Thread-0
In scenarios like the preceding one, avoid using ExecutorService. There is no guarantee that each Runnable (of a given customerId) will be handled by the same thread at every execution. This may lead to weird results.