1616
1717package com .rabbitmq .utility ;
1818
19+ import java .util .concurrent .CountDownLatch ;
1920import java .util .concurrent .TimeoutException ;
21+ import java .util .concurrent .atomic .AtomicReference ;
22+
23+ import static java .util .concurrent .TimeUnit .MILLISECONDS ;
2024
2125/**
2226 * Simple one-shot IPC mechanism. Essentially a one-place buffer that cannot be emptied once filled.
2327 */
2428public class BlockingCell <T > {
25- /** Indicator of not-yet-filledness */
26- private boolean _filled = false ;
2729
28- /** Will be null until a value is supplied, and possibly still then. */
29- private T _value ;
30+ private final AtomicReference < T > value = new AtomicReference <>();
31+ private final CountDownLatch latch = new CountDownLatch ( 1 ) ;
3032
3133 private static final long NANOS_IN_MILLI = 1000L * 1000L ;
3234
3335 private static final long INFINITY = -1 ;
3436
35- /** Instantiate a new BlockingCell waiting for a value of the specified type. */
36- public BlockingCell () {
37- // no special handling required in default constructor
38- }
39-
4037 /**
4138 * Wait for a value, and when one arrives, return it (without clearing it). If there's already a value present, there's no need to wait - the existing value
4239 * is returned.
4340 * @return the waited-for value
4441 *
4542 * @throws InterruptedException if this thread is interrupted
4643 */
47- public synchronized T get () throws InterruptedException {
48- while (!_filled ) {
49- wait ();
50- }
51- return _value ;
44+ public T get () throws InterruptedException {
45+ this .latch .await ();
46+ return this .value .get ();
5247 }
5348
5449 /**
@@ -60,30 +55,27 @@ public synchronized T get() throws InterruptedException {
6055 * @return the waited-for value
6156 * @throws InterruptedException if this thread is interrupted
6257 */
63- public synchronized T get (long timeout ) throws InterruptedException , TimeoutException {
58+ public T get (long timeout ) throws InterruptedException , TimeoutException {
6459 if (timeout == INFINITY ) return get ();
6560
6661 if (timeout < 0 ) {
6762 throw new IllegalArgumentException ("Timeout cannot be less than zero" );
6863 }
6964
70- long now = System .nanoTime () / NANOS_IN_MILLI ;
71- long maxTime = now + timeout ;
72- while (!_filled && (now = (System .nanoTime () / NANOS_IN_MILLI )) < maxTime ) {
73- wait (maxTime - now );
74- }
65+ boolean done = this .latch .await (10 , MILLISECONDS );
7566
76- if (!_filled )
67+ if (!done ) {
7768 throw new TimeoutException ();
69+ }
7870
79- return _value ;
71+ return this . value . get () ;
8072 }
8173
8274 /**
8375 * As get(), but catches and ignores InterruptedException, retrying until a value appears.
8476 * @return the waited-for value
8577 */
86- public synchronized T uninterruptibleGet () {
78+ public T uninterruptibleGet () {
8779 boolean wasInterrupted = false ;
8880 try {
8981 while (true ) {
@@ -128,21 +120,19 @@ public synchronized T uninterruptibleGet(int timeout) throws TimeoutException {
128120 Thread .currentThread ().interrupt ();
129121 }
130122 }
131-
132123 throw new TimeoutException ();
133124 }
134125
135126 /**
136127 * Store a value in this BlockingCell, throwing {@link IllegalStateException} if the cell already has a value.
137128 * @param newValue the new value to store
138129 */
139- public synchronized void set (T newValue ) {
140- if (_filled ) {
130+ public void set (T newValue ) {
131+ if (this .value .compareAndSet (null , newValue )) {
132+ this .latch .countDown ();
133+ } else {
141134 throw new IllegalStateException ("BlockingCell can only be set once" );
142135 }
143- _value = newValue ;
144- _filled = true ;
145- notifyAll ();
146136 }
147137
148138 /**
@@ -151,10 +141,11 @@ public synchronized void set(T newValue) {
151141 * @param newValue the new value to store
152142 */
153143 public synchronized boolean setIfUnset (T newValue ) {
154- if (_filled ) {
144+ if (this .value .compareAndSet (null , newValue )) {
145+ this .latch .countDown ();
146+ return true ;
147+ } else {
155148 return false ;
156149 }
157- set (newValue );
158- return true ;
159150 }
160151}
0 commit comments