I am learning multi threading. I have below code which implements round robin algorithm over an CopyOnWriteArrayList. List will always have a fixed number of elements let’s suppose 10.
AtomicInteger counter = new AtomicInteger(0);
Lock lock = new ReentrantLock(true);
public String get(CopyOnWriteArrayList<String> fruits) {
String next;
try {
lock.lock();
counter.compareAndSet(fruits.size(), 0);
next = fruits.get(counter.getAndIncrement());
}finally {
lock.unlock();
}
return next;
}
Note: List only contains 10 elements not more than that ever.
I am thinking using AtomicInteger is useless here as I am already locking critical section.
Is there a way to use Atomicnteger and not lock. I am using lock as below two lines can generate race conditions.
counter.compareAndSet(fruits.size(), 0);
fruits.get(counter.getAndIncrement());
Trying to create thread safe counter that will be used to get element from List.
I need rotation here as if the counter rises to 10 than it will be reverted back to 0 to implement round robin.
Ahmed Bilal is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
2
I am thinking using AtomicInteger is useless here as I am already
locking critical section.
If counter
is accessed only while the lock is locked then that is correct. An AtomicInteger
provides no advantage over a random other mutable int
wrapper under those circumstances.
Is there a way to use Atomicnteger and not
lock. I am using lock as below two lines can generate race condition.
counter.compareAndSet(fruits.size(), 0);
fruits.get(counter.getAndIncrement());
More specifically, the issue is that fruits.size()
, fruits.get()
, counter.compareAndSet()
and counter.getAndIncrement()
all need to be coherent. That is, to avoid the possibility of the get()
failing with an IndexOutOfBoundsException
despite the list being non-empty, you need the size reported by fruits.size()
not to be larger than the actual size at the time of the fruits.get()
, and you need the value of counter
after the compareAndSet()
to be the same one observed by the getAndIncrement()
.
Trying to create thread safe counter that will be used to get element
from List.
An AtomicInteger
is thread-safe. So is a CopyOnWriteArrayList
. The issue here is that that is not enough. Thus, you have mischaracterized the issue. It is not that you need a thread-safe counter, but rather that you need a thread-safe iterative get()
operation.
You could conceivably use the list’s iterator
instead of retrieving by index. However, that will iterate over a snapshot of the list as of when the iterator was created, and it will not automatically wrap around, both of which distinguish this approach from your idea.
You could conceivably skip the locking and instead catch and recover from an IndexOutOfBoundsException
when one occurs. This is harder than it may sound, and ugly, and left as an exercise.
You have not disclosed the context for this, so that we could decide what alternatives would best serve the purpose, but my best guess would be that you do want to use a lock, and that you probably would be fine with an ordinary int
counter. In that case, you may also need to protect mutations of the list with the same lock, at which point, you would not be getting much advantage from using CopyOnWriteArrayList
in place of a plain ArrayList
.
1