@@ -23,6 +23,7 @@ import org.slf4j.Logger
2323import java .io .Closeable
2424import java .net .URI
2525import java .util .concurrent .atomic .AtomicInteger
26+ import java .util .concurrent .atomic .AtomicReference
2627import scala .language .reflectiveCalls
2728import scala .util .{Failure , Success , Try }
2829
@@ -32,40 +33,26 @@ trait ElasticClientCompanion[T <: Closeable] extends ClientCompanion { _: { def
3233
3334 private val failures = new AtomicInteger (0 )
3435
35- /** Thread-safe client instance using double-checked locking pattern
36- * @volatile
37- * ensures visibility across threads
38- */
39- @ volatile private var client : Option [T ] = None
40-
41- /** Lock object for synchronized initialization
42- */
43- private val lock = new Object ()
36+ private val ref = new AtomicReference [Option [T ]](None )
4437
45- /** Get or create Elastic Client instance (thread-safe, lazy initialization) Uses double-checked
46- * locking for optimal performance
38+ /** Get or create Elastic Client instance (thread-safe) using atomic reference
4739 *
4840 * @return
4941 * Elastic Client instance
5042 * @throws IllegalStateException
5143 * if client creation fails
5244 */
5345 def apply (): T = {
54- // First check (no locking) - fast path for already initialized client
55- client match {
46+ ref.get() match {
5647 case Some (c) => c
57- case None =>
58- // Second check with lock - slow path for initialization
59- lock.synchronized {
60- client match {
61- case Some (c) =>
62- c // Another thread initialized while we were waiting
63- case None =>
64- val c = createClient()
65- client = Some (c)
66- logger.info(s " Elasticsearch Client initialized for ${elasticConfig.credentials.url}" )
67- c
68- }
48+ case None =>
49+ val c = createClient()
50+ if (ref.compareAndSet(None , Some (c))) {
51+ logger.info(s " Elasticsearch Client initialized for ${elasticConfig.credentials.url}" )
52+ c
53+ } else {
54+ // Another thread initialized while we were waiting
55+ ref.get().get
6956 }
7057 }
7158 }
@@ -141,22 +128,20 @@ trait ElasticClientCompanion[T <: Closeable] extends ClientCompanion { _: { def
141128
142129 /** Check if client is initialized and connected
143130 */
144- override def isInitialized : Boolean = client .isDefined
131+ override def isInitialized : Boolean = ref.get() .isDefined
145132
146133 /** Close the client and release resources Idempotent - safe to call multiple times
147134 */
148135 override def close (): Unit = {
149- lock.synchronized {
150- client.foreach { c =>
151- Try {
152- c.close()
153- logger.info(" Elasticsearch Client closed successfully" )
154- }.recover { case ex : Exception =>
155- logger.warn(s " Error closing Elasticsearch Client: ${ex.getMessage}" , ex)
156- }
157- client = None
136+ ref.get().foreach { c =>
137+ Try {
138+ c.close()
139+ logger.info(" Elasticsearch Client closed successfully" )
140+ }.recover { case ex : Exception =>
141+ logger.warn(s " Error closing Elasticsearch Client: ${ex.getMessage}" , ex)
158142 }
159143 }
144+ ref.set(None )
160145 }
161146
162147 /** Reset client (force reconnection on next access) Useful for connection recovery scenarios
0 commit comments