I have a collection of string values available.
I thought of using CopyOnwriteArrayList
or ConcurrentLinkedQueue
initially. But, when I run my code, I see that same string values are picked by one more threads most of the time.
Here is my working code with the lock to serve the purpose:
public class SomeClass {
ReentrantLock lock = new ReentrantLock();
// this list is ensured to have non-duplicate items.
private List<String> bookingIds;
public String read() {
lock.lock();
if (Objects.isNull(bookingIds)) {
bookingIds = bookingInfoUtil.findDistinctId();
}
if (! bookingIds.isEmpty()) {
String bookingId = bookingIds.remove(0);
lock.unlock();
return bookingId;
}
lock.unlock();
return null;
}
}
Now, I want to know how to achieve this with a lock-free mechanism, preferably with a thread-safe collection. As I mentioned above, I tried to use both CopyOnwriteArrayList
or ConcurrentLinkedQueue
and exposed it to a threadpool that actively call read()
method to obtain a unique value. It always fails to attain this goal unless a lock is used. Any better ways to do this?
So, here is the approach that I used:
bookingInfoUtil.findDistinctId()
, outside of read()
so that data is populated before threads reach to read()
method.ConcurrentLinkedQueue
, so that my performance is much better for insert/remove
operation. Also, it doesn't have to re-shuffle the entire list of elements since it is a queue.So, the code is simplified to:
public class SomeClass {
// Value is actually set as a batch job parameter for my case.
// But, you can also set this as a bean or load the values using constructor.
@Value("#{jobParameters[bookingIds]}")
ConcurrentLinkedQueue<String> bookingIds;
public String read() {
if (! bookingIds.isEmpty()) {
return bookingIds.poll();
}
return null;
}
}