-
Bug
-
Resolution: Unresolved
-
P4
-
None
-
8, 11, 17, 21, 25
-
generic
-
generic
A DESCRIPTION OF THE PROBLEM :
LinkedBlockingDeque.clear() should preserve weakly-consistent iterators by linking f.prev and f.next back to f, allowing the iterators to continue from the first or last respectively. This would be consistent with how the other node-based weakly consistent queues LinkedBlockingQueue LinkedTransferQueue, ConcurrentLinkedQueue/Deque work.
The LBD already supports self-linking, since that is done by the unlinkFirst() and unlinkLast() methods, and the iterators and spliterator thus all support self-linking.
This can be fixed very easily by linking both f.prev and f.next back to f.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test code below. Ideally we would want the LinkedBlockingDeque to behave the same as the other concurrent node-based queues. Note that the results for LinkedBlockingDeque are different in the output below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Testing LinkedBlockingQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing LinkedTransferQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing ConcurrentLinkedQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing ConcurrentLinkedDeque
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing LinkedBlockingDeque
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing ArrayBlockingQueue
clear()
1
2
3
false
clear() and add()
1
2
3
while(poll() != null) and add()
1
2
3
ACTUAL -
Testing LinkedBlockingQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing LinkedTransferQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing ConcurrentLinkedQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing ConcurrentLinkedDeque
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing LinkedBlockingDeque
clear()
1
2
3
false
clear() and add()
1
2
3
while(poll() != null) and add()
1
2
3
80
90
100
Testing ArrayBlockingQueue
clear()
1
2
3
false
clear() and add()
1
2
3
while(poll() != null) and add()
1
2
3
---------- BEGIN SOURCE ----------
import java.util.*;
import java.util.concurrent.*;
public class UnlinkingNodesAndWeaklyConsistent {
public static void main(String... args) {
test(new LinkedBlockingQueue<Integer>());
test(new LinkedTransferQueue<Integer>());
test(new ConcurrentLinkedQueue<Integer>());
test(new ConcurrentLinkedDeque<Integer>());
test(new LinkedBlockingDeque<Integer>()); // does not work in its current form
test(new ArrayBlockingQueue<Integer>(20)); // never continues output after clear()
}
private static void test(Queue<Integer> q) {
System.out.println("Testing " + q.getClass().getSimpleName());
Collections.addAll(q, 1, 2, 3, 4, 5, 6);
System.out.println("clear()");
Iterator<Integer> it = q.iterator();
System.out.println(it.next()); // 1
System.out.println(it.next()); // 2
q.clear();
System.out.println(it.next()); // 3 - cached
System.out.println(it.hasNext()); // false
System.out.println("clear() and add()");
Collections.addAll(q, 1, 2, 3, 4, 5, 6);
it = q.iterator();
System.out.println(it.next()); // 1
System.out.println(it.next()); // 2
q.clear();
q.add(80);
q.add(90);
q.add(100);
// preferred output: 3, 80, 90, 100
while (it.hasNext()) {
System.out.println(it.next());
}
q.clear();
System.out.println("while(poll() != null) and add()");
Collections.addAll(q, 1, 2, 3, 4, 5, 6);
it = q.iterator();
System.out.println(it.next()); // 1
System.out.println(it.next()); // 2
while (q.poll() != null) ;
q.add(80);
q.add(90);
q.add(100);
// preferred output: 3, 80, 90, 100
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println();
}
}
---------- END SOURCE ----------
LinkedBlockingDeque.clear() should preserve weakly-consistent iterators by linking f.prev and f.next back to f, allowing the iterators to continue from the first or last respectively. This would be consistent with how the other node-based weakly consistent queues LinkedBlockingQueue LinkedTransferQueue, ConcurrentLinkedQueue/Deque work.
The LBD already supports self-linking, since that is done by the unlinkFirst() and unlinkLast() methods, and the iterators and spliterator thus all support self-linking.
This can be fixed very easily by linking both f.prev and f.next back to f.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test code below. Ideally we would want the LinkedBlockingDeque to behave the same as the other concurrent node-based queues. Note that the results for LinkedBlockingDeque are different in the output below.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Testing LinkedBlockingQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing LinkedTransferQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing ConcurrentLinkedQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing ConcurrentLinkedDeque
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing LinkedBlockingDeque
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing ArrayBlockingQueue
clear()
1
2
3
false
clear() and add()
1
2
3
while(poll() != null) and add()
1
2
3
ACTUAL -
Testing LinkedBlockingQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing LinkedTransferQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing ConcurrentLinkedQueue
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing ConcurrentLinkedDeque
clear()
1
2
3
false
clear() and add()
1
2
3
80
90
100
while(poll() != null) and add()
1
2
3
80
90
100
Testing LinkedBlockingDeque
clear()
1
2
3
false
clear() and add()
1
2
3
while(poll() != null) and add()
1
2
3
80
90
100
Testing ArrayBlockingQueue
clear()
1
2
3
false
clear() and add()
1
2
3
while(poll() != null) and add()
1
2
3
---------- BEGIN SOURCE ----------
import java.util.*;
import java.util.concurrent.*;
public class UnlinkingNodesAndWeaklyConsistent {
public static void main(String... args) {
test(new LinkedBlockingQueue<Integer>());
test(new LinkedTransferQueue<Integer>());
test(new ConcurrentLinkedQueue<Integer>());
test(new ConcurrentLinkedDeque<Integer>());
test(new LinkedBlockingDeque<Integer>()); // does not work in its current form
test(new ArrayBlockingQueue<Integer>(20)); // never continues output after clear()
}
private static void test(Queue<Integer> q) {
System.out.println("Testing " + q.getClass().getSimpleName());
Collections.addAll(q, 1, 2, 3, 4, 5, 6);
System.out.println("clear()");
Iterator<Integer> it = q.iterator();
System.out.println(it.next()); // 1
System.out.println(it.next()); // 2
q.clear();
System.out.println(it.next()); // 3 - cached
System.out.println(it.hasNext()); // false
System.out.println("clear() and add()");
Collections.addAll(q, 1, 2, 3, 4, 5, 6);
it = q.iterator();
System.out.println(it.next()); // 1
System.out.println(it.next()); // 2
q.clear();
q.add(80);
q.add(90);
q.add(100);
// preferred output: 3, 80, 90, 100
while (it.hasNext()) {
System.out.println(it.next());
}
q.clear();
System.out.println("while(poll() != null) and add()");
Collections.addAll(q, 1, 2, 3, 4, 5, 6);
it = q.iterator();
System.out.println(it.next()); // 1
System.out.println(it.next()); // 2
while (q.poll() != null) ;
q.add(80);
q.add(90);
q.add(100);
// preferred output: 3, 80, 90, 100
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println();
}
}
---------- END SOURCE ----------
- links to
-
Review(master) openjdk/jdk/24488