2828import reactor .core .publisher .Mono ;
2929
3030import java .nio .ByteBuffer ;
31- import java .util .concurrent .atomic .AtomicReference ;
31+ import java .util .concurrent .atomic .AtomicReferenceFieldUpdater ;
3232import java .util .function .Function ;
3333
3434import org .reactivestreams .Publisher ;
35-
3635import org .springframework .dao .DataAccessException ;
3736import org .springframework .dao .InvalidDataAccessResourceUsageException ;
3837import org .springframework .data .redis .connection .*;
@@ -48,10 +47,12 @@ class LettuceReactiveRedisConnection implements ReactiveRedisConnection {
4847
4948 static final RedisCodec <ByteBuffer , ByteBuffer > CODEC = ByteBufferCodec .INSTANCE ;
5049
50+ private final Object mutex = new Object ();
51+
5152 private final AsyncConnect <StatefulConnection <ByteBuffer , ByteBuffer >> dedicatedConnection ;
5253 private final AsyncConnect <StatefulRedisPubSubConnection <ByteBuffer , ByteBuffer >> pubSubConnection ;
5354
54- private final LettuceReactivePubSubCommands pubSub = new LettuceReactivePubSubCommands ( this ) ;
55+ private volatile LettuceReactivePubSubCommands pubSub ;
5556
5657 private @ Nullable Mono <StatefulConnection <ByteBuffer , ByteBuffer >> sharedConnection ;
5758
@@ -139,7 +140,13 @@ public ReactiveHyperLogLogCommands hyperLogLogCommands() {
139140
140141 @ Override
141142 public ReactivePubSubCommands pubSubCommands () {
142- return pubSub ;
143+
144+ synchronized (mutex ) {
145+ if (this .pubSub == null ) {
146+ this .pubSub = new LettuceReactivePubSubCommands (this );
147+ }
148+ return pubSub ;
149+ }
143150 }
144151
145152 @ Override
@@ -291,10 +298,13 @@ public ByteBuffer encodeValue(ByteBuffer value) {
291298 */
292299 static class AsyncConnect <T extends io .lettuce .core .api .StatefulConnection <?, ?>> {
293300
301+ static AtomicReferenceFieldUpdater <AsyncConnect , State > STATE = AtomicReferenceFieldUpdater
302+ .newUpdater (AsyncConnect .class , State .class , "state" );
303+
294304 private final Mono <T > connectionPublisher ;
295305 private final LettuceConnectionProvider connectionProvider ;
296306
297- private AtomicReference < State > state = new AtomicReference <>( State .INITIAL ) ;
307+ private volatile State state = State .INITIAL ;
298308 private volatile @ Nullable StatefulConnection <ByteBuffer , ByteBuffer > connection ;
299309
300310 @ SuppressWarnings ("unchecked" )
@@ -310,7 +320,7 @@ static class AsyncConnect<T extends io.lettuce.core.api.StatefulConnection<?, ?>
310320
311321 this .connectionPublisher = defer .doOnNext (it -> {
312322
313- if (isClosing (this . state . get ())) {
323+ if (isClosing (STATE . get (this ))) {
314324 it .closeAsync ();
315325 } else {
316326 connection = it ;
@@ -319,7 +329,7 @@ static class AsyncConnect<T extends io.lettuce.core.api.StatefulConnection<?, ?>
319329 .cache () //
320330 .handle ((connection , sink ) -> {
321331
322- if (isClosing (this . state . get ())) {
332+ if (isClosing (STATE . get (this ))) {
323333 sink .error (new IllegalStateException ("Unable to connect; Connection is closed" ));
324334 } else {
325335 sink .next ((T ) connection );
@@ -335,12 +345,12 @@ static class AsyncConnect<T extends io.lettuce.core.api.StatefulConnection<?, ?>
335345 */
336346 Mono <T > getConnection () {
337347
338- State state = this . state . get ();
348+ State state = STATE . get (this );
339349 if (isClosing (state )) {
340350 return Mono .error (new IllegalStateException ("Unable to connect; Connection is closed" ));
341351 }
342352
343- this . state . compareAndSet (State .INITIAL , State .CONNECTION_REQUESTED );
353+ STATE . compareAndSet (this , State .INITIAL , State .CONNECTION_REQUESTED );
344354
345355 return connectionPublisher ;
346356 }
@@ -352,12 +362,13 @@ Mono<Void> close() {
352362
353363 return Mono .defer (() -> {
354364
355- if (state .compareAndSet (State .INITIAL , CLOSING ) || state .compareAndSet (State .CONNECTION_REQUESTED , CLOSING )) {
365+ if (STATE .compareAndSet (this , State .INITIAL , CLOSING )
366+ || STATE .compareAndSet (this , State .CONNECTION_REQUESTED , CLOSING )) {
356367
357368 StatefulConnection <ByteBuffer , ByteBuffer > connection = this .connection ;
358369 this .connection = null ;
359370
360- state .set (State .CLOSED );
371+ STATE .set (this , State .CLOSED );
361372 if (connection != null ) {
362373 return Mono .fromCompletionStage (connectionProvider .releaseAsync (connection ));
363374 }
0 commit comments