Skip to content

Synchronize forEach() in SynchronizedCollection - #720

Merged
garydgregory merged 2 commits into
apache:masterfrom
rootvector2:synchronized-collection-foreach-lock
Aug 1, 2026
Merged

Synchronize forEach() in SynchronizedCollection#720
garydgregory merged 2 commits into
apache:masterfrom
rootvector2:synchronized-collection-foreach-lock

Conversation

@rootvector2

Copy link
Copy Markdown
Contributor

noticed while diffing the overridden method list against java.util.Collections.synchronizedCollection: SynchronizedCollection guards removeIf but never overrides forEach, so the inherited default walks the deliberately unsynchronized iterator() and a concurrent writer trips ConcurrentModificationException; delegating forEach under lock covers SynchronizedBag, SynchronizedSortedBag, SynchronizedMultiSet, SynchronizedSortedMultiSet and SynchronizedQueue too since they all extend it, while stream() and spliterator() stay unsynchronized for the same reason the JDK leaves them so: their traversal happens after the lock would be released.

  • Read the contribution guidelines for this project.
  • Read the ASF Generative Tooling Guidance if you use Artificial Intelligence (AI).
  • I used AI to create any part of, or all of, this pull request. Which AI tool was used to create this pull request, and to what extent did it contribute?
  • Run a successful build using the default Maven goal with mvn; that's mvn on the command line by itself.
  • Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible, but it is a best practice.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Each commit in the pull request should have a meaningful subject line and body.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns org.apache.commons.collections4.collection.SynchronizedCollection with java.util.Collections.synchronizedCollection by synchronizing forEach(...) on the decorator’s lock, preventing traversal via the deliberately-unsynchronized iterator() default implementation.

Changes:

  • Override SynchronizedCollection#forEach(Consumer) to delegate under synchronized (lock).
  • Add a parameterized JUnit 5 test that asserts forEach executes while holding the decorator monitor across all affected synchronized decorators.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/main/java/org/apache/commons/collections4/collection/SynchronizedCollection.java Adds a forEach override synchronized on lock to avoid unsynchronized iteration.
src/test/java/org/apache/commons/collections4/collection/SynchronizedCollectionTest.java Adds parameterized coverage ensuring forEach holds the expected lock for multiple synchronized decorators.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@garydgregory garydgregory changed the title synchronize forEach in SynchronizedCollection Synchronize forEach() in SynchronizedCollection Aug 1, 2026
@garydgregory

Copy link
Copy Markdown
Member

Thank you @rootvector2 , merged 🚀

@garydgregory
garydgregory merged commit 6ee9dd7 into apache:master Aug 1, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants