Skip to content

Replace synchronized with ReentrantLock in Topic.doMessageSend() to reduce lock contention #1798

@jeanouii

Description

@jeanouii

Topic.doMessageSend() is currently synchronized, holding the intrinsic lock during persistence, dispatch to all subscribers, and persistence completion wait. Under high contention (many concurrent producers + durable subscribers + slow persistence), this serializes all work unnecessarily.

This change replaces synchronized with a ReentrantLock held only during persistence (to guarantee message ordering as javadoc was mentioning). Dispatch to subscribers and result.get() happen outside the lock, allowing concurrent dispatch for messages from different producers.

This is valid per Jakarta Messaging 3.1 Section 6.2.9: message ordering is guaranteed per-session/per-producer only.

JMH benchmarks on my old MacBook Pro M1 show +15% to +41% throughput improvement under contention (10+ producer threads, multiple durable subscribers, H2 JDBC or simulated IO latency). Single-thread performance is unchanged.

On a real production system, the gain under heavy load with a lot of subscribers (several thousands) and a JDBC backend is huge.

I've Included a JMH benchmark (TopicSendLockBenchmark.java, excluded from CI).

Metadata

Metadata

Assignees

Labels

javaPull requests that update java code

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions