@@ -195,31 +195,53 @@ private boolean casTail(Node c, Node v) {
195195 return U .compareAndSetReference (this , TAIL , c , v );
196196 }
197197
198- /** tries once to CAS a new dummy node for head */
199- private void tryInitializeHead () {
200- Node h = new ExclusiveNode ();
201- if (U .compareAndSetReference (this , HEAD , null , h ))
202- tail = h ;
198+ /**
199+ * Tries to CAS a new dummy node for head.
200+ * Returns new tail, or null if OutOfMemory
201+ */
202+ private Node tryInitializeHead () {
203+ for (Node h = null , t ;;) {
204+ if ((t = tail ) != null )
205+ return t ;
206+ else if (head != null )
207+ Thread .onSpinWait ();
208+ else {
209+ if (h == null ) {
210+ try {
211+ h = new ExclusiveNode ();
212+ } catch (OutOfMemoryError oome ) {
213+ return null ;
214+ }
215+ }
216+ if (U .compareAndSetReference (this , HEAD , null , h ))
217+ return tail = h ;
218+ }
219+ }
203220 }
204221
222+
205223 /**
206224 * Enqueues the node unless null. (Currently used only for
207225 * ConditionNodes; other cases are interleaved with acquires.)
208226 */
209- final void enqueue (Node node ) {
227+ final void enqueue (ConditionNode node ) {
210228 if (node != null ) {
211- for (;;) {
212- Node t = tail ;
229+ boolean unpark = false ;
230+ for (Node t ;;) {
231+ if ((t = tail ) == null && (t = tryInitializeHead ()) == null ) {
232+ unpark = true ; // wake up to spin on OOME
233+ break ;
234+ }
213235 node .setPrevRelaxed (t ); // avoid unnecessary fence
214- if (t == null ) // initialize
215- tryInitializeHead ();
216- else if (casTail (t , node )) {
236+ if (casTail (t , node )) {
217237 t .next = node ;
218238 if (t .status < 0 ) // wake up to clean link
219- LockSupport . unpark ( node . waiter ) ;
239+ unpark = true ;
220240 break ;
221241 }
222242 }
243+ if (unpark )
244+ LockSupport .unpark (node .waiter );
223245 }
224246 }
225247
@@ -278,7 +300,10 @@ final int acquire(Node node, long arg, boolean shared,
278300 * Check if node now first
279301 * if so, ensure head stable, else ensure valid predecessor
280302 * if node is first or not yet enqueued, try acquiring
303+ * else if queue is not initialized, do so by attaching new header node
304+ * resort to spinwait on OOME trying to create node
281305 * else if node not yet created, create it
306+ * resort to spinwait on OOME trying to create node
282307 * else if not yet enqueued, try once to enqueue
283308 * else if woken from park, retry (up to postSpins times)
284309 * else if WAITING status not set, set and retry
@@ -321,18 +346,20 @@ final int acquire(Node node, long arg, boolean shared,
321346 return 1 ;
322347 }
323348 }
324- if (node == null ) { // allocate; retry before enqueue
325- if (shared )
326- node = new SharedNode ();
327- else
328- node = new ExclusiveNode ();
349+ Node t ;
350+ if ((t = tail ) == null ) { // initialize queue
351+ if (tryInitializeHead () == null )
352+ return acquireOnOOME (shared , arg );
353+ } else if (node == null ) { // allocate; retry before enqueue
354+ try {
355+ node = (shared ) ? new SharedNode () : new ExclusiveNode ();
356+ } catch (OutOfMemoryError oome ) {
357+ return acquireOnOOME (shared , arg );
358+ }
329359 } else if (pred == null ) { // try to enqueue
330360 node .waiter = current ;
331- Node t = tail ;
332361 node .setPrevRelaxed (t ); // avoid unnecessary fence
333- if (t == null )
334- tryInitializeHead ();
335- else if (!casTail (t , node ))
362+ if (!casTail (t , node ))
336363 node .setPrevRelaxed (null ); // back out
337364 else
338365 t .next = node ;
@@ -358,9 +385,23 @@ else if ((nanos = time - System.nanoTime()) > 0L)
358385 return cancelAcquire (node , interrupted , interruptible );
359386 }
360387
388+ /**
389+ * Spin-waits with backoff; used only upon OOME failures during acquire.
390+ */
391+ private int acquireOnOOME (boolean shared , long arg ) {
392+ for (long nanos = 1L ;;) {
393+ if (shared ? (tryAcquireShared (arg ) >= 0 ) : tryAcquire (arg ))
394+ return 1 ;
395+ U .park (false , nanos ); // must use Unsafe park to sleep
396+ if (nanos < 1L << 30 ) // max about 1 second
397+ nanos <<= 1 ;
398+ }
399+ }
400+
361401 /**
362402 * Possibly repeatedly traverses from tail, unsplicing cancelled
363- * nodes until none are found.
403+ * nodes until none are found. Unparks nodes that may have been
404+ * relinked to be next eligible acquirer.
364405 */
365406 private void cleanQueue () {
366407 for (;;) { // restart point
@@ -1067,6 +1108,12 @@ public class ConditionObject implements Condition, java.io.Serializable {
10671108 /** Last node of condition queue. */
10681109 private transient ConditionNode lastWaiter ;
10691110
1111+ /**
1112+ * Fixed delay in nanoseconds between releasing and reacquiring
1113+ * lock during Condition waits that encounter OutOfMemoryErrors
1114+ */
1115+ static final long OOME_COND_WAIT_DELAY = 10L * 1000L * 1000L ; // 10 ms
1116+
10701117 /**
10711118 * Creates a new {@code ConditionObject} instance.
10721119 */
@@ -1103,7 +1150,7 @@ public final void signal() {
11031150 ConditionNode first = firstWaiter ;
11041151 if (!isHeldExclusively ())
11051152 throw new IllegalMonitorStateException ();
1106- if (first != null )
1153+ else if (first != null )
11071154 doSignal (first , false );
11081155 }
11091156
@@ -1118,7 +1165,7 @@ public final void signalAll() {
11181165 ConditionNode first = firstWaiter ;
11191166 if (!isHeldExclusively ())
11201167 throw new IllegalMonitorStateException ();
1121- if (first != null )
1168+ else if (first != null )
11221169 doSignal (first , true );
11231170 }
11241171
@@ -1185,6 +1232,26 @@ private void unlinkCancelledWaiters(ConditionNode node) {
11851232 }
11861233 }
11871234
1235+ /**
1236+ * Constructs objects needed for condition wait. On OOME,
1237+ * releases lock, sleeps, reacquires, and returns null.
1238+ */
1239+ private ConditionNode newConditionNode () {
1240+ long savedState ;
1241+ if (tryInitializeHead () != null ) {
1242+ try {
1243+ return new ConditionNode ();
1244+ } catch (OutOfMemoryError oome ) {
1245+ }
1246+ }
1247+ // fall through if encountered OutOfMemoryError
1248+ if (!isHeldExclusively () || !release (savedState = getState ()))
1249+ throw new IllegalMonitorStateException ();
1250+ U .park (false , OOME_COND_WAIT_DELAY );
1251+ acquireOnOOME (false , savedState );
1252+ return null ;
1253+ }
1254+
11881255 /**
11891256 * Implements uninterruptible condition wait.
11901257 * <ol>
@@ -1197,7 +1264,9 @@ private void unlinkCancelledWaiters(ConditionNode node) {
11971264 * </ol>
11981265 */
11991266 public final void awaitUninterruptibly () {
1200- ConditionNode node = new ConditionNode ();
1267+ ConditionNode node = newConditionNode ();
1268+ if (node == null )
1269+ return ;
12011270 long savedState = enableWait (node );
12021271 LockSupport .setCurrentBlocker (this ); // for back-compatibility
12031272 boolean interrupted = false , rejected = false ;
@@ -1241,7 +1310,9 @@ else if ((node.status & COND) != 0) {
12411310 public final void await () throws InterruptedException {
12421311 if (Thread .interrupted ())
12431312 throw new InterruptedException ();
1244- ConditionNode node = new ConditionNode ();
1313+ ConditionNode node = newConditionNode ();
1314+ if (node == null )
1315+ return ;
12451316 long savedState = enableWait (node );
12461317 LockSupport .setCurrentBlocker (this ); // for back-compatibility
12471318 boolean interrupted = false , cancelled = false , rejected = false ;
@@ -1292,7 +1363,9 @@ public final long awaitNanos(long nanosTimeout)
12921363 throws InterruptedException {
12931364 if (Thread .interrupted ())
12941365 throw new InterruptedException ();
1295- ConditionNode node = new ConditionNode ();
1366+ ConditionNode node = newConditionNode ();
1367+ if (node == null )
1368+ return nanosTimeout - OOME_COND_WAIT_DELAY ;
12961369 long savedState = enableWait (node );
12971370 long nanos = (nanosTimeout < 0L ) ? 0L : nanosTimeout ;
12981371 long deadline = System .nanoTime () + nanos ;
@@ -1336,7 +1409,9 @@ public final boolean awaitUntil(Date deadline)
13361409 long abstime = deadline .getTime ();
13371410 if (Thread .interrupted ())
13381411 throw new InterruptedException ();
1339- ConditionNode node = new ConditionNode ();
1412+ ConditionNode node = newConditionNode ();
1413+ if (node == null )
1414+ return false ;
13401415 long savedState = enableWait (node );
13411416 boolean cancelled = false , interrupted = false ;
13421417 while (!canReacquire (node )) {
@@ -1377,7 +1452,9 @@ public final boolean await(long time, TimeUnit unit)
13771452 long nanosTimeout = unit .toNanos (time );
13781453 if (Thread .interrupted ())
13791454 throw new InterruptedException ();
1380- ConditionNode node = new ConditionNode ();
1455+ ConditionNode node = newConditionNode ();
1456+ if (node == null )
1457+ return false ;
13811458 long savedState = enableWait (node );
13821459 long nanos = (nanosTimeout < 0L ) ? 0L : nanosTimeout ;
13831460 long deadline = System .nanoTime () + nanos ;
0 commit comments