This is an automated email from the ASF dual-hosted git repository.
lizhimin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/rocketmq-clients.git
The following commit(s) were added to refs/heads/master by this push:
new fd58daba [ISSUE #1145] Make ClientServiceProvider.loadService
Thread-Safe with Lazy Initialization (#1146)
fd58daba is described below
commit fd58dabaa43c4218344b87f6bbcf1251bfb9b5b8
Author: qianye <[email protected]>
AuthorDate: Wed Dec 10 13:58:18 2025 +0800
[ISSUE #1145] Make ClientServiceProvider.loadService Thread-Safe with Lazy
Initialization (#1146)
---
.../client/apis/ClientServiceProvider.java | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git
a/java/client-apis/src/main/java/org/apache/rocketmq/client/apis/ClientServiceProvider.java
b/java/client-apis/src/main/java/org/apache/rocketmq/client/apis/ClientServiceProvider.java
index 723ca2e2..39df3a5c 100644
---
a/java/client-apis/src/main/java/org/apache/rocketmq/client/apis/ClientServiceProvider.java
+++
b/java/client-apis/src/main/java/org/apache/rocketmq/client/apis/ClientServiceProvider.java
@@ -30,7 +30,47 @@ import
org.apache.rocketmq.client.apis.producer.ProducerBuilder;
* <a href="https://en.wikipedia.org/wiki/Service_provider_interface">Java SPI
mechanism</a>.
*/
public interface ClientServiceProvider {
+
+ /**
+ * To avoid potential concurrency issues, the {@link #loadService()} logic
+ * has been changed to use lazy initialization with caching:
+ * <p>
+ * 1. Lazy loading + caching:
+ * - On the first call, the implementation is loaded via {@link
ServiceLoader}
+ * and cached in {@link Holder#INSTANCE};
+ * - Subsequent calls simply return the cached instance.
+ * <p>
+ * 2. If you need the old behavior (i.e., always load through ServiceLoader
+ * each time), you can call {@link #doLoad()} directly:
+ * - {@link #doLoad()} does not cache anything; it creates a new
ServiceLoader
+ * and loads an implementation on every call;
+ * - You are responsible for handling any concurrency control when using
+ * {@link #doLoad()} directly.
+ */
+
+ class Holder {
+ static volatile ClientServiceProvider INSTANCE;
+
+ private Holder() {
+ // prevents instantiation
+ }
+ }
+
static ClientServiceProvider loadService() {
+ ClientServiceProvider inst = Holder.INSTANCE;
+ if (inst != null) {
+ return inst;
+ }
+ synchronized (ClientServiceProvider.class) {
+ if (Holder.INSTANCE != null) {
+ return Holder.INSTANCE;
+ }
+ Holder.INSTANCE = doLoad();
+ return Holder.INSTANCE;
+ }
+ }
+
+ static ClientServiceProvider doLoad() {
final ServiceLoader<ClientServiceProvider> loaders =
ServiceLoader.load(ClientServiceProvider.class);
final Iterator<ClientServiceProvider> iterators = loaders.iterator();
if (iterators.hasNext()) {