Skip to content

Commit e360995

Browse files
committed
Extend RC.10 with a note about containsAll(), addAll(), removeAll(), and putAll()
1 parent 923df24 commit e360995

File tree

1 file changed

+20
-4
lines changed

1 file changed

+20
-4
lines changed

README.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ Race conditions
6262
](#unsafe-concurrent-iteration)
6363
- [A non-thread-safe collection is *not* returned wrapped in `Collections.unmodifiable*()` from
6464
a getter in a thread-safe class?](#unsafe-concurrent-iteration)
65+
- [A synchronized collection is not returned from a getter? in a thread-safe class?
66+
](#unsafe-concurrent-iteration)
6567
- [Non-trivial mutable object is *not* returned from a getter in a thread-safe class?
6668
](#concurrent-mutation-race)
6769
- [No separate getters to an atomically updated state?](#moving-state-race)
@@ -78,7 +80,9 @@ Race conditions
7880
- [Concurrent invalidation race is not possible on a lazily initialized state?
7981
](#cache-invalidation-race)
8082
- [Iteration, Stream pipeline, or copying a `Collections.synchronized*()` collection is protected
81-
by a lock?](#synchronized-collection-iter)
83+
by the lock?](#synchronized-collection-iter)
84+
- [A synchronized collection is passed into `addAll()`, `removeAll()`, or `putAll()` under the
85+
lock?](#synchronized-collection-iter)
8286

8387
Testing
8488
- [Unit tests for thread-safe classes are multi-threaded?](#multi-threaded-tests)
@@ -717,9 +721,21 @@ more scalable than Guava Cache: see [Sc.9](#caffeine).
717721
Stream pipeline using a synchronized collection as a source is protected by `synchronized (coll)`?**
718722
See [the Javadoc](
719723
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collections.html#synchronizedCollection(java.util.Collection))
720-
for examples and details. This also applies to passing synchronized collections into copy
721-
constructors or static factory methods of other collections because they implicitly iterate over the
722-
source collection.
724+
for examples and details.
725+
726+
This also applies to passing synchronized collections into:
727+
- Copy constructors of other collections, e. g. `new ArrayList<>(synchronizedList)`
728+
- Static factory methods of other collections, e. g. `List.copyOf()`, `Set.copyOf()`,
729+
`ImmutableMap.copyOf()`
730+
- Bulk methods on other collections:
731+
- `otherColl.containsAll(synchronizedColl)`
732+
- `otherColl.addAll(synchronizedColl)`
733+
- `otherColl.removeAll(synchronizedColl)`
734+
- `otherMap.putAll(synchronizedMap)`
735+
- `otherColl.containsAll(synchronizedMap.keySet())`
736+
- Etc.
737+
738+
Because in all these cases there is an implicit iteration on the source collection.
723739

724740
See also [RC.3](#unsafe-concurrent-iteration) about unprotected iteration over non-thread-safe
725741
collections.

0 commit comments

Comments
 (0)