Skip to content

Fix ConcurrentHashMap contention in ExtensionHolderFactoryImpl#2816

Merged
jtduffy merged 2 commits intonewrelic:mainfrom
rdara:fix/concurrent-hashmap-contention-case-00311074
Apr 6, 2026
Merged

Fix ConcurrentHashMap contention in ExtensionHolderFactoryImpl#2816
jtduffy merged 2 commits intonewrelic:mainfrom
rdara:fix/concurrent-hashmap-contention-case-00311074

Conversation

@rdara
Copy link
Copy Markdown
Contributor

@rdara rdara commented Mar 31, 2026

Before contributing, please read our contributing guidelines and code of conduct.

Overview

Replace computeIfAbsent() with putIfAbsent pattern to avoid bin-level locking during value creation. This prevents thread contention issues where threads get stuck in ConcurrentHashMap.helpTransfer() under high concurrency scenarios.

The fix uses a double-check pattern:

  1. Fast path check with get()
  2. Create value outside any lock
  3. Atomic putIfAbsent - only one thread wins

Trade-off: Under race conditions, multiple threads may create extension instances, but only one wins. This is safe because valueLoader creates empty/stateless instances.

This issue was observed in production environments with high thread counts causing application hangs due to ConcurrentHashMap internal contention.

Ref: NewRelic Support Case #00311074

Related Github Issue

N/A - Issue reported via NewRelic Support Case #00311074

Testing

 - Verified fix resolves thread contention in production environment with high thread counts
 - Existing test suite should pass as the change maintains the same functional behavior
 - 

Checks

  • Your contributions are backwards compatible with relevant frameworks and APIs.
  • Your code does not contain any breaking changes. Otherwise please describe.
  • Your code does not introduce any new dependencies. Otherwise please describe.

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Mar 31, 2026

CLA assistant check
All committers have signed the CLA.

rdara added 2 commits March 31, 2026 12:11
Replace computeIfAbsent() with putIfAbsent pattern to avoid bin-level
locking during value creation. This prevents thread contention issues
where threads get stuck in ConcurrentHashMap.helpTransfer() under high
concurrency scenarios.

The fix uses a double-check pattern:
1. Fast path check with get()
2. Create value outside any lock
3. Atomic putIfAbsent - only one thread wins

Trade-off: Under race conditions, multiple threads may create extension
instances, but only one wins. This is safe because valueLoader creates
empty/stateless instances.

This issue was observed in production environments with high thread counts
causing application hangs due to ConcurrentHashMap internal contention.

Ref: NewRelic Support Case #00311074
Tests verify:
- Basic get/remove extension functionality
- High concurrency access to same instance key
- High concurrency access with different instance keys
- Contention scenario with slow value loader

These tests confirm the putIfAbsent pattern handles concurrent access
without causing thread contention issues.
@rdara rdara force-pushed the fix/concurrent-hashmap-contention-case-00311074 branch from 0154129 to 5f7d937 Compare March 31, 2026 19:11
@jtduffy
Copy link
Copy Markdown
Contributor

jtduffy commented Apr 6, 2026

@rdara
Thanks for the contribution! This will be in our next release (v9.2.0) which should be available by the end of this week or early next week, assuming no surprises.

@jtduffy jtduffy merged commit 3741c17 into newrelic:main Apr 6, 2026
297 of 301 checks passed
@github-project-automation github-project-automation bot moved this from Triage to Code Complete/Done in Java Engineering Board Apr 6, 2026
jtduffy added a commit that referenced this pull request Apr 6, 2026
…ntention-case-00311074"

This reverts commit 3741c17, reversing
changes made to 1e43c50.
kanderson250 added a commit that referenced this pull request Apr 6, 2026
Revert "Merge pull request #2816 from rdara/fix/concurrent-hashmap-contention-case-00311074"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Code Complete/Done

Development

Successfully merging this pull request may close these issues.

3 participants