Updating Java PriorityQueue when its elements change priority
You have to remove and re-insert, as the queue works by putting new elements in the appropriate position when they are inserted. This is much faster than the alternative of finding the highest-priority element every time you pull out of the queue. The drawback is that you cannot change the priority after the element has been inserted. A TreeMap has the same limitation (as does a HashMap, which also breaks when the hashcode of its elements changes after insertion).
If you want to write a wrapper, you can move the comparison code from enqueue to dequeue. You would not need to sort at enqueue time anymore (because the order it creates would not be reliable anyway if you allow changes).
But this will perform worse, and you want to synchronize on the queue if you change any of the priorities. Since you need to add synchronization code when updating priorities, you might as well just dequeue and enqueue (you need the reference to the queue in both cases).
Changing the priority of an element in a PriorityQueue
Remove the object, change its priority, and re-add it to the queue.
My intuition is that the data structure doesn't normally watch the internal state of the objects and that it requires an add() or remove() operation to trigger a re-invocation of the comparator. A call to Collections.sort(), would also work, but you would have to transform the queue to a list and then back to a queue. This might make more sense if you change a lot of priorities at one time.
Better still, you might update n priorities, then add and remove the last one.
Updating Java PriorityQueue when its elements change priority
You have to remove and re-insert, as the queue works by putting new elements in the appropriate position when they are inserted. This is much faster than the alternative of finding the highest-priority element every time you pull out of the queue. The drawback is that you cannot change the priority after the element has been inserted. A TreeMap has the same limitation (as does a HashMap, which also breaks when the hashcode of its elements changes after insertion).
If you want to write a wrapper, you can move the comparison code from enqueue to dequeue. You would not need to sort at enqueue time anymore (because the order it creates would not be reliable anyway if you allow changes).
But this will perform worse, and you want to synchronize on the queue if you change any of the priorities. Since you need to add synchronization code when updating priorities, you might as well just dequeue and enqueue (you need the reference to the queue in both cases).
Updating a PriorityQueue when iterating it
This code is in the Java 6 implementation of PriorityQueue:
private class Itr implements Iterator<E> {
/**
* The modCount value that the iterator believes that the backing
* Queue should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
private int expectedModCount = modCount;
public E next() {
if(expectedModCount != modCount) {
throw new ConcurrentModificationException();
}
}
}
Now, why is this code here? If you look at the Javadoc for ConcurrentModificationException you will find that the behaviour of an iterator is undefined if modification occurs to the underlying collection before iteration completes. As such, many of the collections implement this modCount
mechanism.
To fix your code
You need to ensure that you don't modify the code mid-loop. If your code is single threaded (as it appears to be) then you can simply do as your coworker suggested and copy it into a list for later inclusion. Also, the use of the Iterator.remove() method is documented to prevent ConcurrentModificationExceptions. An example:
List<Entry> toAdd = new ArrayList<Entry>();
Iterator it = mEntries.iterator();
while(it.hasNext()) {
Entry e = it.next();
if(e.getId().equals(someId)) {
Entry newEntry = e.setData(newData);
it.remove();
toAdd.add(newEntry);
}
}
mEntries.addAll(toAdd);
PriorityQueue changes elements positions on poll()
PriorityQueue only claims to make the first entry in correct order. If you iterate over the PriorityQueue you can see all but the first element in any order and it may change as you add/remove entries.
From the Javadoc for PriorityQueue
The Iterator provided in method iterator() is not guaranteed to traverse the elements of the priority queue in any particular order. If you need ordered traversal, consider using Arrays.sort(pq.toArray()).
If you need correct ordering at all times I suggest using TreeSet.
NavigableSet<MyType> orderedSeedQueue = new TreeSet<>(new MyComparator());
// add elements
while(!orderSeedQueue.isEmpty()) {
firstItem = orderSeedQueue.pollFirst();
However, depending on your use case it may be simpler to sort them.
List<MyType> types = ...
Collections.sort(types, new MyComparator());
for(MyType t : types) { // in sorted order
Related Topics
Findviewbyid Returns Null in a Dialog
How to Write Ndef Records to Nfc Tag
How to Create the Directory Error
How to Execute Linux Commands on a Remote MAChine Using Java
Variable Is Accessed Within Inner Class. Needs to Be Declared Final
How to Change a Textview's Style at Runtime
Retrofit Expected Begin_Object But Was Begin_Array
Delete Data from Arraylist with a For-Loop
Change Background Color of Single Specific Menu Items of Navigationview
Listview Is Blank While Using Getfilter Function
How to Generate Random Number in Specific Range in Android
Return a Value from Asynctask in Android
Sending a JSON Http Post Request from Android
Where's My Invalid Character (Ora-00911)
Why Call Super() in a Constructor