I have N threads that add values and one removing thread. I am thinking of the best way how to sync adding to existing list of values and removing of the list.
I guess following case is possible:
thread 1 checked condition containsKey, and entered in else block
thread 2 removed the value
thread 1 try to add value to existing list, and get returns null
I think the only approach that I can use is syncing by map value, in our case is List when we adding and when we deleting
private ConcurrentSkipListMap<LocalDateTime, List<Task>> tasks = new ConcurrentSkipListMap<>();
//Thread1,3...N
public void add(LocalDateTime time, Task task) {
if (!tasks.containsKey(time)) {
tasks.computeIfAbsent(time, k -> createValue(task));
} else {
//potentially should be synced
tasks.get(time).add(task);
}
}
private List<Task> createValue(Task val) {
return new ArrayList<>(Arrays.asList(val));
}
//thread 2
public void remove()
while(true){
Map.Entry<LocalDateTime, List<Task>> keyVal = tasks.firstEntry();
if (isSomeCondition(keyVal)) {
tasks.remove(keyVal.getKey());
for (Task t : keyVal.getValue()) {
//do task processing
}
}
}
}
About the add
part you would be really inclined to use merge
, but the documentation is pretty clear about it - saying that it is not guaranteed to happen atomically.
I would replace your add
with merge
, but under a lock.
SomeLock lock ...
public void add(LocalDateTime time, Task task) {
lock.lock();
tasks.merge...
lock.unlock();
}
And same for the remove
method. But then, if you are doing things under a lock there is no need for ConcurrentSkipListMap
in the first place.
On the other hand if you are OK changing to ConcurrentHashMap
- it has merge
that is atomic for example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With