I'm starting a long-running process on a queue of items, and while an item is either scheduled to be processed or is being processed, I want to disallow some other operation. My code basically looks like this:
public class LongRunningProcess extends Thread {
private final ConcurrentLinkedQueue<Item> pending = new ConcurrentLinkedQueue<>();
private final Set<Item> active = Collections.newSetFromMap(new ConcurrentHashMap<Item, Boolean>());
public LongRunningProcess() {
// add items to pending; no more items will ever be added
}
@Override
public void run() {
while (! pending.isEmpty()) {
// The peek/add/remove pattern here is important. The number
// of items that are active or scheduled is always decreasing.
// Because isScheduled checks pending before checking active,
// this order of operations ensures that we never miss an item
// as it is being switched from one collection to the other.
Item nextItem = pending.peek();
active.add(nextItem); // <---Can any of these get reordered?
pending.remove(); // <---+
processItem(nextItem); // <---+
active.remove(nextItem); // <---+
}
}
public boolean isScheduled(Item item) {
return pending.contains(item) || active.contains(item);
}
}
Will this work the way I expect, or is it possible for the highlighted code block above to be reordered? Can you please point me to any relevant specs?
Edit:
@Banthar's helpful comment led me to the java.util.concurrent package documentation, which answers my question definitively:
The methods of all classes in
java.util.concurrent
and its subpackages extend these guarantees to higher-level synchronization. In particular:
- Actions in a thread prior to placing an object into any concurrent collection happen-before actions subsequent to the access or removal of that element from the collection in another thread.