Merge JEP-349-branch
authormgronlun
Sun, 15 Sep 2019 13:41:19 +0200
branchJEP-349-branch
changeset 58157 9dca61a7df19
parent 58156 68031e660872 (current diff)
parent 58140 a6f653312b19 (diff)
child 58158 369ebc2a11c2
Merge
src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
src/hotspot/share/jfr/jfr.cpp
src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp
src/hotspot/share/jfr/leakprofiler/chains/edgeStore.hpp
src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp
src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp
src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp
src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp
src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp
src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp
src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp
src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.hpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp
src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp
src/hotspot/share/jfr/recorder/repository/jfrChunk.hpp
src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp
src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp
src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp
src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.cpp
src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp
src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp
src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp
src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp
src/hotspot/share/jfr/support/jfrThreadLocal.cpp
src/hotspot/share/jfr/support/jfrThreadLocal.hpp
src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp
src/hotspot/share/jfr/utilities/jfrBlob.cpp
src/hotspot/share/jfr/utilities/jfrBlob.hpp
src/hotspot/share/jfr/utilities/jfrHashtable.hpp
src/hotspot/share/jfr/utilities/jfrTypes.hpp
src/hotspot/share/jfr/writers/jfrTypeWriterHost.hpp
--- a/make/autoconf/toolchain_windows.m4	Sat Sep 14 13:18:20 2019 +0200
+++ b/make/autoconf/toolchain_windows.m4	Sun Sep 15 13:41:19 2019 +0200
@@ -808,7 +808,7 @@
   if test "x$USE_UCRT" = "xtrue"; then
     AC_MSG_CHECKING([for UCRT DLL dir])
     if test "x$with_ucrt_dll_dir" != x; then
-      if test -z "$(ls -d $with_ucrt_dll_dir/*.dll 2> /dev/null)"; then
+      if test -z "$(ls -d "$with_ucrt_dll_dir/"*.dll 2> /dev/null)"; then
         AC_MSG_RESULT([no])
         AC_MSG_ERROR([Could not find any dlls in $with_ucrt_dll_dir])
       else
--- a/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp	Sun Sep 15 13:41:19 2019 +0200
@@ -55,19 +55,19 @@
   return !_edges->has_entries();
 }
 
-void EdgeStore::link(EdgeEntry* entry) {
+void EdgeStore::on_link(EdgeEntry* entry) {
   assert(entry != NULL, "invariant");
   assert(entry->id() == 0, "invariant");
   entry->set_id(++_edge_id_counter);
 }
 
-bool EdgeStore::equals(uintptr_t hash, const EdgeEntry* entry) {
+bool EdgeStore::on_equals(uintptr_t hash, const EdgeEntry* entry) {
   assert(entry != NULL, "invariant");
   assert(entry->hash() == hash, "invariant");
   return true;
 }
 
-void EdgeStore::unlink(EdgeEntry* entry) {
+void EdgeStore::on_unlink(EdgeEntry* entry) {
   assert(entry != NULL, "invariant");
   // nothing
 }
--- a/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.hpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.hpp	Sun Sep 15 13:41:19 2019 +0200
@@ -74,9 +74,9 @@
   EdgeHashTable* _edges;
 
   // Hash table callbacks
-  void link(EdgeEntry* entry);
-  bool equals(uintptr_t hash, const EdgeEntry* entry);
-  void unlink(EdgeEntry* entry);
+  void on_link(EdgeEntry* entry);
+  bool on_equals(uintptr_t hash, const EdgeEntry* entry);
+  void on_unlink(EdgeEntry* entry);
 
   StoredEdge* get(const oop* reference) const;
   StoredEdge* put(const oop* reference);
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp	Sun Sep 15 13:41:19 2019 +0200
@@ -181,9 +181,9 @@
   JfrBlobHandle get(const ObjectSample* sample);
   void put(const ObjectSample* sample, const JfrBlobHandle& blob);
   // Hash table callbacks
-  void link(const BlobEntry* entry) const;
-  bool equals(uintptr_t hash, const BlobEntry* entry) const;
-  void unlink(BlobEntry* entry) const;
+  void on_link(const BlobEntry* entry) const;
+  bool on_equals(uintptr_t hash, const BlobEntry* entry) const;
+  void on_unlink(BlobEntry* entry) const;
 };
 
 JfrBlobHandle BlobCache::get(const ObjectSample* sample) {
@@ -202,19 +202,19 @@
   _table.put(sample->stack_trace_hash(), blob);
 }
 
-inline void BlobCache::link(const BlobEntry* entry) const {
+inline void BlobCache::on_link(const BlobEntry* entry) const {
   assert(entry != NULL, "invariant");
   assert(entry->id() == 0, "invariant");
   entry->set_id(_lookup_id);
 }
 
-inline bool BlobCache::equals(uintptr_t hash, const BlobEntry* entry) const {
+inline bool BlobCache::on_equals(uintptr_t hash, const BlobEntry* entry) const {
   assert(entry != NULL, "invariant");
   assert(entry->hash() == hash, "invariant");
   return entry->id() == _lookup_id;
 }
 
-inline void BlobCache::unlink(BlobEntry* entry) const {
+inline void BlobCache::on_unlink(BlobEntry* entry) const {
   assert(entry != NULL, "invariant");
 }
 
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp	Sun Sep 15 13:41:19 2019 +0200
@@ -146,18 +146,18 @@
   FieldInfoTable* _table;
   const ObjectSampleFieldInfo* _lookup;
 
-  void link(FieldInfoEntry* entry) {
+  void on_link(FieldInfoEntry* entry) {
     assert(entry != NULL, "invariant");
     entry->set_id(++_field_id_counter);
   }
 
-  bool equals(uintptr_t hash, const FieldInfoEntry* entry) {
+  bool on_equals(uintptr_t hash, const FieldInfoEntry* entry) {
     assert(hash == entry->hash(), "invariant");
     assert(_lookup != NULL, "invariant");
     return entry->literal()->_field_modifiers == _lookup->_field_modifiers;
   }
 
-  void unlink(FieldInfoEntry* entry) {
+  void on_unlink(FieldInfoEntry* entry) {
     assert(entry != NULL, "invariant");
     // nothing
   }
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp	Sun Sep 15 13:41:19 2019 +0200
@@ -276,8 +276,6 @@
   TypeSetSerialization(bool class_unload, bool flushpoint, JfrCheckpointWriter* leakp_writer = NULL) :
     _leakp_writer(leakp_writer), _elements(0), _class_unload(class_unload), _flushpoint(flushpoint) {}
   void write(JfrCheckpointWriter& writer) {
-    MutexLocker cld_lock(SafepointSynchronize::is_at_safepoint() ? NULL : ClassLoaderDataGraph_lock);
-    MutexLocker lock(SafepointSynchronize::is_at_safepoint() ? NULL : Module_lock);
    _elements = JfrTypeSet::serialize(&writer, _leakp_writer, _class_unload, _flushpoint);
   }
   size_t elements() const {
@@ -290,16 +288,17 @@
   type_set.write(writer);
 };
 
+TypeSet::TypeSet(JfrCheckpointWriter* leakp_writer) : _leakp_writer(leakp_writer) {}
+
 void FlushTypeSet::serialize(JfrCheckpointWriter& writer) {
   assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
-  TypeSetSerialization type_set(false, true);
-  type_set.write(writer);
+  TypeSetSerialization type_set(false);
+    type_set.write(writer, &leakp_writer);
   _elements = type_set.elements();
 }
 
 size_t FlushTypeSet::elements() const {
-  return _elements;
-}
+    return;
 
 TypeSet::TypeSet(JfrCheckpointWriter* leakp_writer) : _leakp_writer(leakp_writer) {}
 
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp	Sun Sep 15 13:41:19 2019 +0200
@@ -173,6 +173,9 @@
 
 void JfrTypeManager::write_type_set() {
   assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
+  // can safepoint here because of Module_lock
+  MutexLocker cld_lock(SafepointSynchronize::is_at_safepoint() ? NULL : ClassLoaderDataGraph_lock);
+  MutexLocker lock(SafepointSynchronize::is_at_safepoint() ? NULL : Module_lock);
   if (!LeakProfiler::is_running()) {
     JfrCheckpointWriter writer;
     TypeSet set;
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp	Sun Sep 15 13:41:19 2019 +0200
@@ -78,7 +78,7 @@
   _class_unload = class_unload;
 }
 
-void JfrSymbolId::link(const SymbolEntry* entry) {
+void JfrSymbolId::on_link(const SymbolEntry* entry) {
   assert(entry != NULL, "invariant");
   const_cast<Symbol*>(entry->literal())->increment_refcount();
   assert(entry->id() == 0, "invariant");
@@ -87,19 +87,18 @@
   _sym_list = entry;
 }
 
-bool JfrSymbolId::equals(uintptr_t hash, const SymbolEntry* entry) {
+bool JfrSymbolId::on_equals(uintptr_t hash, const SymbolEntry* entry) {
   // query might be NULL
   assert(entry != NULL, "invariant");
   assert(entry->hash() == hash, "invariant");
   return true;
 }
 
-void JfrSymbolId::unlink(const SymbolEntry* entry) {
   assert(entry != NULL, "invariant");
   const_cast<Symbol*>(entry->literal())->decrement_refcount();
 }
 
-void JfrSymbolId::link(const CStringEntry* entry) {
+void JfrSymbolId::on_link(const CStringEntry* entry) {
   assert(entry != NULL, "invariant");
   assert(entry->id() == 0, "invariant");
   entry->set_id(++_symbol_id_counter);
@@ -107,13 +106,13 @@
   _cstring_list = entry;
 }
 
-bool JfrSymbolId::equals(uintptr_t hash, const CStringEntry* entry) {
+bool JfrSymbolId::on_equals(uintptr_t hash, const CStringEntry* entry) {
   assert(entry != NULL, "invariant");
   assert(entry->hash() == hash, "invariant");
   return true;
 }
 
-void JfrSymbolId::unlink(const CStringEntry* entry) {
+void JfrSymbolId::on_unlink(const CStringEntry* entry) {
   assert(entry != NULL, "invariant");
   JfrCHeapObj::free(const_cast<char*>(entry->literal()), strlen(entry->literal() + 1));
 }
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Sun Sep 15 13:41:19 2019 +0200
@@ -226,12 +226,12 @@
   bool _class_unload;
 
   // hashtable(s) callbacks
-  void link(const SymbolEntry* entry);
-  bool equals(uintptr_t hash, const SymbolEntry* entry);
-  void unlink(const SymbolEntry* entry);
-  void link(const CStringEntry* entry);
-  bool equals(uintptr_t hash, const CStringEntry* entry);
-  void unlink(const CStringEntry* entry);
+  void on_link(const SymbolEntry* entry);
+  bool on_equals(uintptr_t hash, const SymbolEntry* entry);
+  void on_unlink(const SymbolEntry* entry);
+  void on_link(const CStringEntry* entry);
+  bool on_equals(uintptr_t hash, const CStringEntry* entry);
+  void on_unlink(const CStringEntry* entry);
 
   template <typename Functor, typename T>
   void iterate(Functor& functor, const T* list) {
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp	Sun Sep 15 13:41:19 2019 +0200
@@ -44,7 +44,7 @@
   _start_nanos(0),
   _previous_start_nanos(invalid_time),
   _last_update_nanos(0),
-  _last_checkpoint_offset(0),
+  _last_checkpoint_offset(0) {}
   _last_metadata_offset(0),
   _generation(1) {}
 
--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp	Sun Sep 15 13:41:19 2019 +0200
@@ -140,8 +140,6 @@
   const size_t processed = _entries;
   _entries = 0;
   return processed;
-}
-
 traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
   assert(thread == Thread::current(), "invariant");
   JfrThreadLocal* const tl = thread->jfr_thread_local();
--- a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp	Sun Sep 15 13:41:19 2019 +0200
@@ -100,10 +100,12 @@
   assert(jt != NULL, "invariant");
   assert(Thread::current() == jt, "invariant");
   assert(jt->jfr_thread_local()->trace_id() == id, "invariant");
-  EventThreadEnd event;
-  event.set_thread(id);
-  event.commit();
-  JfrThreadCPULoadEvent::send_event_for_thread(jt);
+  if (JfrRecorder::is_recording()) {
+    EventThreadEnd event;
+    event.set_thread(id);
+    event.commit();
+    JfrThreadCPULoadEvent::send_event_for_thread(jt);
+  }
 }
 
 void JfrThreadLocal::release(JfrThreadLocal* tl, Thread* t) {
--- a/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp	Sun Sep 15 13:41:19 2019 +0200
@@ -26,6 +26,7 @@
 #define SHARE_JFR_SUPPORT_JFRTRACEIDEXTENSION_HPP
 
 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp"
+#include "utilities/macros.hpp"
 
 #define DEFINE_TRACE_ID_FIELD mutable traceid _trace_id
 
@@ -59,10 +60,19 @@
   }
 
   jbyte* flags_addr() const {
+#ifdef VM_LITTLE_ENDIAN
     return (jbyte*)&_flags;
+#else
+    return ((jbyte*)&_flags) + 1;
+#endif
   }
+
   jbyte* meta_addr() const {
+#ifdef VM_LITTLE_ENDIAN
     return ((jbyte*)&_flags) + 1;
+#else
+    return (jbyte*)&_flags;
+#endif
   }
 };
 
--- a/src/hotspot/share/jfr/utilities/jfrHashtable.hpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/hotspot/share/jfr/utilities/jfrHashtable.hpp	Sun Sep 15 13:41:19 2019 +0200
@@ -93,7 +93,6 @@
   }
   void free_buckets() {
     FREE_C_HEAP_ARRAY(Bucket, _buckets);
-    _buckets = NULL;
   }
   TableEntry* bucket(size_t i) { return _buckets[i].get_entry();}
   TableEntry** bucket_addr(size_t i) { return _buckets[i].entry_addr(); }
@@ -114,12 +113,12 @@
  public:
   AscendingId() : _id(0) {}
   // callbacks
-  void link(Entry* entry) {
+  void on_link(Entry* entry) {
     assert(entry != NULL, "invariant");
     assert(entry->id() == 0, "invariant");
     entry->set_id(++_id);
   }
-  bool equals(uintptr_t hash, const Entry* entry) {
+  bool on_equals(uintptr_t hash, const Entry* entry) {
     assert(entry->hash() == hash, "invariant");
     return true;
   }
@@ -185,7 +184,7 @@
   void free_entry(HashEntry* entry) {
     assert(entry != NULL, "invariant");
     JfrBasicHashtable<T>::unlink_entry(entry);
-    _callback->unlink(entry);
+    _callback->on_unlink(entry);
     delete entry;
   }
 
@@ -195,7 +194,7 @@
   HashEntry* new_entry(uintptr_t hash, const T& data);
   void add_entry(size_t index, HashEntry* new_entry) {
     assert(new_entry != NULL, "invariant");
-    _callback->link(new_entry);
+    _callback->on_link(new_entry);
     assert(new_entry->id() > 0, "invariant");
     JfrBasicHashtable<T>::add_entry(index, new_entry);
   }
@@ -213,7 +212,7 @@
 Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::lookup_only(uintptr_t hash) {
   HashEntry* entry = (HashEntry*)this->bucket(index_for(hash));
   while (entry != NULL) {
-    if (entry->hash() == hash && _callback->equals(hash, entry)) {
+    if (entry->hash() == hash && _callback->on_equals(hash, entry)) {
       return entry;
     }
     entry = (HashEntry*)entry->next();
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java	Sun Sep 15 13:41:19 2019 +0200
@@ -385,7 +385,7 @@
      * cases where old nodes can be reused because their next fields
      * won't change.  On average, only about one-sixth of them need
      * cloning when a table doubles. The nodes they replace will be
-     * garbage collectable as soon as they are no longer referenced by
+     * garbage collectible as soon as they are no longer referenced by
      * any reader thread that may be in the midst of concurrently
      * traversing table.  Upon transfer, the old table bin contains
      * only a special forwarding node (with hash field "MOVED") that
@@ -3286,9 +3286,8 @@
             return true;
         }
 
-        private static final Unsafe U = Unsafe.getUnsafe();
         private static final long LOCKSTATE
-                = U.objectFieldOffset(TreeBin.class, "lockState");
+            = U.objectFieldOffset(TreeBin.class, "lockState");
     }
 
     /* ----------------Table Traversal -------------- */
@@ -6345,28 +6344,20 @@
 
     // Unsafe mechanics
     private static final Unsafe U = Unsafe.getUnsafe();
-    private static final long SIZECTL;
-    private static final long TRANSFERINDEX;
-    private static final long BASECOUNT;
-    private static final long CELLSBUSY;
-    private static final long CELLVALUE;
-    private static final int ABASE;
+    private static final long SIZECTL
+        = U.objectFieldOffset(ConcurrentHashMap.class, "sizeCtl");
+    private static final long TRANSFERINDEX
+        = U.objectFieldOffset(ConcurrentHashMap.class, "transferIndex");
+    private static final long BASECOUNT
+        = U.objectFieldOffset(ConcurrentHashMap.class, "baseCount");
+    private static final long CELLSBUSY
+        = U.objectFieldOffset(ConcurrentHashMap.class, "cellsBusy");
+    private static final long CELLVALUE
+        = U.objectFieldOffset(CounterCell.class, "value");
+    private static final int ABASE = U.arrayBaseOffset(Node[].class);
     private static final int ASHIFT;
 
     static {
-        SIZECTL = U.objectFieldOffset
-            (ConcurrentHashMap.class, "sizeCtl");
-        TRANSFERINDEX = U.objectFieldOffset
-            (ConcurrentHashMap.class, "transferIndex");
-        BASECOUNT = U.objectFieldOffset
-            (ConcurrentHashMap.class, "baseCount");
-        CELLSBUSY = U.objectFieldOffset
-            (ConcurrentHashMap.class, "cellsBusy");
-
-        CELLVALUE = U.objectFieldOffset
-            (CounterCell.class, "value");
-
-        ABASE = U.arrayBaseOffset(Node[].class);
         int scale = U.arrayIndexScale(Node[].class);
         if ((scale & (scale - 1)) != 0)
             throw new ExceptionInInitializerError("array index scale not a power of two");
--- a/src/java.base/share/classes/java/util/concurrent/Phaser.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/Phaser.java	Sun Sep 15 13:41:19 2019 +0200
@@ -97,7 +97,7 @@
  *       associated recovery within handlers of those exceptions,
  *       often after invoking {@code forceTermination}.  Phasers may
  *       also be used by tasks executing in a {@link ForkJoinPool}.
- *       Progress is ensured if the pool's parallelismLevel can
+ *       Progress is ensured if the pool's parallelism level can
  *       accommodate the maximum number of simultaneously blocked
  *       parties.
  *
--- a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Sun Sep 15 13:41:19 2019 +0200
@@ -1053,18 +1053,18 @@
 
     // Unsafe mechanics
     private static final Unsafe U = Unsafe.getUnsafe();
-    private static final long SEED = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomSeed");
-    private static final long PROBE = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomProbe");
-    private static final long SECONDARY = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomSecondarySeed");
-    private static final long THREADLOCALS = U.objectFieldOffset
-            (Thread.class, "threadLocals");
-    private static final long INHERITABLETHREADLOCALS = U.objectFieldOffset
-            (Thread.class, "inheritableThreadLocals");
-    private static final long INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
-            (Thread.class, "inheritedAccessControlContext");
+    private static final long SEED
+        = U.objectFieldOffset(Thread.class, "threadLocalRandomSeed");
+    private static final long PROBE
+        = U.objectFieldOffset(Thread.class, "threadLocalRandomProbe");
+    private static final long SECONDARY
+        = U.objectFieldOffset(Thread.class, "threadLocalRandomSecondarySeed");
+    private static final long THREADLOCALS
+        = U.objectFieldOffset(Thread.class, "threadLocals");
+    private static final long INHERITABLETHREADLOCALS
+        = U.objectFieldOffset(Thread.class, "inheritableThreadLocals");
+    private static final long INHERITEDACCESSCONTROLCONTEXT
+        = U.objectFieldOffset(Thread.class, "inheritedAccessControlContext");
 
     /** Rarely-used holder for the second of a pair of Gaussians */
     private static final ThreadLocal<Double> nextLocalGaussian =
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java	Sun Sep 15 13:41:19 2019 +0200
@@ -38,6 +38,7 @@
 import java.lang.invoke.VarHandle;
 import java.util.function.IntBinaryOperator;
 import java.util.function.IntUnaryOperator;
+import jdk.internal.misc.Unsafe;
 
 /**
  * An {@code int} value that may be updated atomically.  See the
@@ -58,8 +59,9 @@
      * This class intended to be implemented using VarHandles, but there
      * are unresolved cyclic startup dependencies.
      */
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long VALUE
+        = U.objectFieldOffset(AtomicInteger.class, "value");
 
     private volatile int value;
 
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java	Sun Sep 15 13:41:19 2019 +0200
@@ -38,6 +38,7 @@
 import java.lang.invoke.VarHandle;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongUnaryOperator;
+import jdk.internal.misc.Unsafe;
 
 /**
  * A {@code long} value that may be updated atomically.  See the
@@ -72,8 +73,9 @@
      * This class intended to be implemented using VarHandles, but there
      * are unresolved cyclic startup dependencies.
      */
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long VALUE = U.objectFieldOffset(AtomicLong.class, "value");
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long VALUE
+        = U.objectFieldOffset(AtomicLong.class, "value");
 
     private volatile long value;
 
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Sun Sep 15 13:41:19 2019 +0200
@@ -35,13 +35,12 @@
 
 package java.util.concurrent.locks;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.AbstractQueuedSynchronizer.Node;
+import java.util.concurrent.ForkJoinPool;
+import jdk.internal.misc.Unsafe;
 
 /**
  * A version of {@link AbstractQueuedSynchronizer} in
@@ -73,23 +72,76 @@
      * keep it that way.
      */
 
-    /**
-     * Creates a new {@code AbstractQueuedLongSynchronizer} instance
-     * with initial synchronization state of zero.
-     */
-    protected AbstractQueuedLongSynchronizer() { }
+    // Node status bits, also used as argument and return values
+    static final int WAITING   = 1;          // must be 1
+    static final int CANCELLED = 0x80000000; // must be negative
+    static final int COND      = 2;          // in a condition wait
+
+    /** CLH Nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
+
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
+
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
+
+    // Concrete classes tagged by type
+    static final class ExclusiveNode extends Node { }
+    static final class SharedNode extends Node { }
+
+    static final class ConditionNode extends Node
+        implements ForkJoinPool.ManagedBlocker {
+        ConditionNode nextWaiter;            // link to next waiting node
+
+        /**
+         * Allows Conditions to be used in ForkJoinPools without
+         * risking fixed pool exhaustion. This is usable only for
+         * untimed Condition waits, not timed versions.
+         */
+        public final boolean isReleasable() {
+            return status <= 1 || Thread.currentThread().isInterrupted();
+        }
+
+        public final boolean block() {
+            while (!isReleasable()) LockSupport.park(this);
+            return true;
+        }
+    }
 
     /**
-     * Head of the wait queue, lazily initialized.  Except for
-     * initialization, it is modified only via method setHead.  Note:
-     * If head exists, its waitStatus is guaranteed not to be
-     * CANCELLED.
+     * Head of the wait queue, lazily initialized.
      */
     private transient volatile Node head;
 
     /**
-     * Tail of the wait queue, lazily initialized.  Modified only via
-     * method enq to add new wait node.
+     * Tail of the wait queue. After initialization, modified only via casTail.
      */
     private transient volatile Node tail;
 
@@ -113,8 +165,7 @@
      * @param newState the new state value
      */
     protected final void setState(long newState) {
-        // See JDK-8180620: Clarify VarHandle mixed-access subtleties
-        STATE.setVolatile(this, newState);
+        state = newState;
     }
 
     /**
@@ -129,481 +180,234 @@
      *         value was not equal to the expected value.
      */
     protected final boolean compareAndSetState(long expect, long update) {
-        return STATE.compareAndSet(this, expect, update);
+        return U.compareAndSetLong(this, STATE, expect, update);
     }
 
     // Queuing utilities
 
-    /**
-     * The number of nanoseconds for which it is faster to spin
-     * rather than to use timed park. A rough estimate suffices
-     * to improve responsiveness with very short timeouts.
-     */
-    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new ExclusiveNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
 
     /**
-     * Inserts node into queue, initializing if necessary. See picture above.
-     * @param node the node to insert
-     * @return node's predecessor
+     * Enqueues the node unless null. (Currently used only for
+     * ConditionNodes; other cases are interleaved with acquires.)
      */
-    private Node enq(Node node) {
-        for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return oldTail;
+    final void enqueue(Node node) {
+        if (node != null) {
+            for (;;) {
+                Node t = tail;
+                node.setPrevRelaxed(t);        // avoid unnecessary fence
+                if (t == null)                 // initialize
+                    tryInitializeHead();
+                else if (casTail(t, node)) {
+                    t.next = node;
+                    if (t.status < 0)          // wake up to clean link
+                        LockSupport.unpark(node.waiter);
+                    break;
                 }
-            } else {
-                initializeSyncQueue();
             }
         }
     }
 
+    /** Returns true if node is found in traversal from tail */
+    final boolean isEnqueued(Node node) {
+        for (Node t = tail; t != null; t = t.prev)
+            if (t == node)
+                return true;
+        return false;
+    }
+
     /**
-     * Creates and enqueues node for current thread and given mode.
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
+     */
+    private static void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /** Wakes up the given node if in shared mode */
+    private static void signalNextIfShared(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null &&
+            (s instanceof SharedNode) && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /**
+     * Main acquire method, invoked by all exported acquire methods.
      *
-     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
-     * @return the new node
+     * @param node null unless a reacquiring Condition
+     * @param arg the acquire argument
+     * @param shared true if shared mode else exclusive
+     * @param interruptible if abort and return negative on interrupt
+     * @param timed if true use timed waits
+     * @param time if timed, the System.nanoTime value to timeout
+     * @return positive if acquired, 0 if timed out, negative if interrupted
      */
-    private Node addWaiter(Node mode) {
-        Node node = new Node(mode);
+    final int acquire(Node node, long arg, boolean shared,
+                      boolean interruptible, boolean timed, long time) {
+        Thread current = Thread.currentThread();
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        Node pred = null;                // predecessor of node when enqueued
+
+        /*
+         * Repeatedly:
+         *  Check if node now first
+         *    if so, ensure head stable, else ensure valid predecessor
+         *  if node is first or not yet enqueued, try acquiring
+         *  else if node not yet created, create it
+         *  else if not yet enqueued, try once to enqueue
+         *  else if woken from park, retry (up to postSpins times)
+         *  else if WAITING status not set, set and retry
+         *  else park and clear WAITING status, and check cancellation
+         */
 
         for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return node;
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
+            }
+            if (first || pred == null) {
+                boolean acquired;
+                try {
+                    if (shared)
+                        acquired = (tryAcquireShared(arg) >= 0);
+                    else
+                        acquired = tryAcquire(arg);
+                } catch (Throwable ex) {
+                    cancelAcquire(node, interrupted, false);
+                    throw ex;
+                }
+                if (acquired) {
+                    if (first) {
+                        node.prev = null;
+                        head = node;
+                        pred.next = null;
+                        node.waiter = null;
+                        if (shared)
+                            signalNextIfShared(node);
+                        if (interrupted)
+                            current.interrupt();
+                    }
+                    return 1;
                 }
+            }
+            if (node == null) {                 // allocate; retry before enqueue
+                if (shared)
+                    node = new SharedNode();
+                else
+                    node = new ExclusiveNode();
+            } else if (pred == null) {          // try to enqueue
+                node.waiter = current;
+                Node t = tail;
+                node.setPrevRelaxed(t);         // avoid unnecessary fence
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {
+                --spins;                        // reduce unfairness on rewaits
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                node.status = WAITING;          // enable signal and recheck
             } else {
-                initializeSyncQueue();
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted, interruptible);
+    }
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
             }
         }
     }
 
     /**
-     * Sets head of queue to be node, thus dequeuing. Called only by
-     * acquire methods.  Also nulls out unused fields for sake of GC
-     * and to suppress unnecessary signals and traversals.
-     *
-     * @param node the node
-     */
-    private void setHead(Node node) {
-        head = node;
-        node.thread = null;
-        node.prev = null;
-    }
-
-    /**
-     * Wakes up node's successor, if one exists.
-     *
-     * @param node the node
-     */
-    private void unparkSuccessor(Node node) {
-        /*
-         * If status is negative (i.e., possibly needing signal) try
-         * to clear in anticipation of signalling.  It is OK if this
-         * fails or if status is changed by waiting thread.
-         */
-        int ws = node.waitStatus;
-        if (ws < 0)
-            node.compareAndSetWaitStatus(ws, 0);
-
-        /*
-         * Thread to unpark is held in successor, which is normally
-         * just the next node.  But if cancelled or apparently null,
-         * traverse backwards from tail to find the actual
-         * non-cancelled successor.
-         */
-        Node s = node.next;
-        if (s == null || s.waitStatus > 0) {
-            s = null;
-            for (Node p = tail; p != node && p != null; p = p.prev)
-                if (p.waitStatus <= 0)
-                    s = p;
-        }
-        if (s != null)
-            LockSupport.unpark(s.thread);
-    }
-
-    /**
-     * Release action for shared mode -- signals successor and ensures
-     * propagation. (Note: For exclusive mode, release just amounts
-     * to calling unparkSuccessor of head if it needs signal.)
-     */
-    private void doReleaseShared() {
-        /*
-         * Ensure that a release propagates, even if there are other
-         * in-progress acquires/releases.  This proceeds in the usual
-         * way of trying to unparkSuccessor of head if it needs
-         * signal. But if it does not, status is set to PROPAGATE to
-         * ensure that upon release, propagation continues.
-         * Additionally, we must loop in case a new node is added
-         * while we are doing this. Also, unlike other uses of
-         * unparkSuccessor, we need to know if CAS to reset status
-         * fails, if so rechecking.
-         */
-        for (;;) {
-            Node h = head;
-            if (h != null && h != tail) {
-                int ws = h.waitStatus;
-                if (ws == Node.SIGNAL) {
-                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
-                        continue;            // loop to recheck cases
-                    unparkSuccessor(h);
-                }
-                else if (ws == 0 &&
-                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
-                    continue;                // loop on failed CAS
-            }
-            if (h == head)                   // loop if head changed
-                break;
-        }
-    }
-
-    /**
-     * Sets head of queue, and checks if successor may be waiting
-     * in shared mode, if so propagating if either propagate > 0 or
-     * PROPAGATE status was set.
-     *
-     * @param node the node
-     * @param propagate the return value from a tryAcquireShared
-     */
-    private void setHeadAndPropagate(Node node, long propagate) {
-        Node h = head; // Record old head for check below
-        setHead(node);
-        /*
-         * Try to signal next queued node if:
-         *   Propagation was indicated by caller,
-         *     or was recorded (as h.waitStatus either before
-         *     or after setHead) by a previous operation
-         *     (note: this uses sign-check of waitStatus because
-         *      PROPAGATE status may transition to SIGNAL.)
-         * and
-         *   The next node is waiting in shared mode,
-         *     or we don't know, because it appears null
-         *
-         * The conservatism in both of these checks may cause
-         * unnecessary wake-ups, but only when there are multiple
-         * racing acquires/releases, so most need signals now or soon
-         * anyway.
-         */
-        if (propagate > 0 || h == null || h.waitStatus < 0 ||
-            (h = head) == null || h.waitStatus < 0) {
-            Node s = node.next;
-            if (s == null || s.isShared())
-                doReleaseShared();
-        }
-    }
-
-    // Utilities for various versions of acquire
-
-    /**
      * Cancels an ongoing attempt to acquire.
      *
-     * @param node the node
-     */
-    private void cancelAcquire(Node node) {
-        // Ignore if node doesn't exist
-        if (node == null)
-            return;
-
-        node.thread = null;
-
-        // Skip cancelled predecessors
-        Node pred = node.prev;
-        while (pred.waitStatus > 0)
-            node.prev = pred = pred.prev;
-
-        // predNext is the apparent node to unsplice. CASes below will
-        // fail if not, in which case, we lost race vs another cancel
-        // or signal, so no further action is necessary, although with
-        // a possibility that a cancelled node may transiently remain
-        // reachable.
-        Node predNext = pred.next;
-
-        // Can use unconditional write instead of CAS here.
-        // After this atomic step, other Nodes can skip past us.
-        // Before, we are free of interference from other threads.
-        node.waitStatus = Node.CANCELLED;
-
-        // If we are the tail, remove ourselves.
-        if (node == tail && compareAndSetTail(node, pred)) {
-            pred.compareAndSetNext(predNext, null);
-        } else {
-            // If successor needs signal, try to set pred's next-link
-            // so it will get one. Otherwise wake it up to propagate.
-            int ws;
-            if (pred != head &&
-                ((ws = pred.waitStatus) == Node.SIGNAL ||
-                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
-                pred.thread != null) {
-                Node next = node.next;
-                if (next != null && next.waitStatus <= 0)
-                    pred.compareAndSetNext(predNext, next);
-            } else {
-                unparkSuccessor(node);
-            }
-
-            node.next = node; // help GC
-        }
-    }
-
-    /**
-     * Checks and updates status for a node that failed to acquire.
-     * Returns true if thread should block. This is the main signal
-     * control in all acquire loops.  Requires that pred == node.prev.
-     *
-     * @param pred node's predecessor holding status
-     * @param node the node
-     * @return {@code true} if thread should block
-     */
-    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
-        int ws = pred.waitStatus;
-        if (ws == Node.SIGNAL)
-            /*
-             * This node has already set status asking a release
-             * to signal it, so it can safely park.
-             */
-            return true;
-        if (ws > 0) {
-            /*
-             * Predecessor was cancelled. Skip over predecessors and
-             * indicate retry.
-             */
-            do {
-                node.prev = pred = pred.prev;
-            } while (pred.waitStatus > 0);
-            pred.next = node;
-        } else {
-            /*
-             * waitStatus must be 0 or PROPAGATE.  Indicate that we
-             * need a signal, but don't park yet.  Caller will need to
-             * retry to make sure it cannot acquire before parking.
-             */
-            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
-        }
-        return false;
-    }
-
-    /**
-     * Convenience method to interrupt current thread.
-     */
-    static void selfInterrupt() {
-        Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Convenience method to park and then check if interrupted.
-     *
-     * @return {@code true} if interrupted
-     */
-    private final boolean parkAndCheckInterrupt() {
-        LockSupport.park(this);
-        return Thread.interrupted();
-    }
-
-    /*
-     * Various flavors of acquire, varying in exclusive/shared and
-     * control modes.  Each is mostly the same, but annoyingly
-     * different.  Only a little bit of factoring is possible due to
-     * interactions of exception mechanics (including ensuring that we
-     * cancel if tryAcquire throws exception) and other control, at
-     * least not without hurting performance too much.
-     */
-
-    /**
-     * Acquires in exclusive uninterruptible mode for thread already in
-     * queue. Used by condition wait methods as well as acquire.
-     *
-     * @param node the node
-     * @param arg the acquire argument
-     * @return {@code true} if interrupted while waiting
-     */
-    final boolean acquireQueued(final Node node, long arg) {
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return interrupted;
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            if (interrupted)
-                selfInterrupt();
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive interruptible mode.
-     * @param arg the acquire argument
+     * @param node the node (may be null if cancelled before enqueuing)
+     * @param interrupted true if thread interrupted
+     * @param interruptible if should report interruption vs reset
      */
-    private void doAcquireInterruptibly(long arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireNanos(long arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return true;
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
+    private int cancelAcquire(Node node, boolean interrupted,
+                              boolean interruptible) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            if (node.prev != null)
+                cleanQueue();
         }
-    }
-
-    /**
-     * Acquires in shared uninterruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireShared(long arg) {
-        final Node node = addWaiter(Node.SHARED);
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    long r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        } finally {
-            if (interrupted)
-                selfInterrupt();
+        if (interrupted) {
+            if (interruptible)
+                return CANCELLED;
+            else
+                Thread.currentThread().interrupt();
         }
-    }
-
-    /**
-     * Acquires in shared interruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireSharedInterruptibly(long arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    long r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in shared timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireSharedNanos(long arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    long r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return true;
-                    }
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
+        return 0;
     }
 
     // Main exported methods
@@ -756,9 +560,8 @@
      *        can represent anything you like.
      */
     public final void acquire(long arg) {
-        if (!tryAcquire(arg) &&
-            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
-            selfInterrupt();
+        if (!tryAcquire(arg))
+            acquire(null, arg, false, false, false, 0L);
     }
 
     /**
@@ -776,11 +579,10 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireInterruptibly(long arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (!tryAcquire(arg) && acquire(null, arg, false, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (!tryAcquire(arg))
-            doAcquireInterruptibly(arg);
     }
 
     /**
@@ -801,11 +603,20 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final boolean tryAcquireNanos(long arg, long nanosTimeout)
-            throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquire(arg) ||
-            doAcquireNanos(arg, nanosTimeout);
+        throws InterruptedException {
+        if (!Thread.interrupted()) {
+            if (tryAcquire(arg))
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, false, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -820,9 +631,7 @@
      */
     public final boolean release(long arg) {
         if (tryRelease(arg)) {
-            Node h = head;
-            if (h != null && h.waitStatus != 0)
-                unparkSuccessor(h);
+            signalNext(head);
             return true;
         }
         return false;
@@ -841,7 +650,7 @@
      */
     public final void acquireShared(long arg) {
         if (tryAcquireShared(arg) < 0)
-            doAcquireShared(arg);
+            acquire(null, arg, true, false, false, 0L);
     }
 
     /**
@@ -858,11 +667,11 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireSharedInterruptibly(long arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (tryAcquireShared(arg) < 0 &&
+             acquire(null, arg, true, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (tryAcquireShared(arg) < 0)
-            doAcquireSharedInterruptibly(arg);
     }
 
     /**
@@ -883,10 +692,19 @@
      */
     public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout)
             throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquireShared(arg) >= 0 ||
-            doAcquireSharedNanos(arg, nanosTimeout);
+        if (!Thread.interrupted()) {
+            if (tryAcquireShared(arg) >= 0)
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, true, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -900,7 +718,7 @@
      */
     public final boolean releaseShared(long arg) {
         if (tryReleaseShared(arg)) {
-            doReleaseShared();
+            signalNext(head);
             return true;
         }
         return false;
@@ -918,7 +736,7 @@
      */
     public final boolean hasQueuedThreads() {
         for (Node p = tail, h = head; p != h && p != null; p = p.prev)
-            if (p.waitStatus <= 0)
+            if (p.status >= 0)
                 return true;
         return false;
     }
@@ -948,45 +766,16 @@
      *         {@code null} if no threads are currently queued
      */
     public final Thread getFirstQueuedThread() {
-        // handle only fast path, else relay
-        return (head == tail) ? null : fullGetFirstQueuedThread();
-    }
-
-    /**
-     * Version of getFirstQueuedThread called when fastpath fails.
-     */
-    private Thread fullGetFirstQueuedThread() {
-        /*
-         * The first node is normally head.next. Try to get its
-         * thread field, ensuring consistent reads: If thread
-         * field is nulled out or s.prev is no longer head, then
-         * some other thread(s) concurrently performed setHead in
-         * between some of our reads. We try this twice before
-         * resorting to traversal.
-         */
-        Node h, s;
-        Thread st;
-        if (((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null) ||
-            ((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null))
-            return st;
-
-        /*
-         * Head's next field might not have been set yet, or may have
-         * been unset after setHead. So we must check to see if tail
-         * is actually first node. If not, we continue on, safely
-         * traversing from tail back to head to find first,
-         * guaranteeing termination.
-         */
-
-        Thread firstThread = null;
-        for (Node p = tail; p != null && p != head; p = p.prev) {
-            Thread t = p.thread;
-            if (t != null)
-                firstThread = t;
+        Thread first = null, w; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null)) {
+            // traverse from tail on stale reads
+            for (Node p = tail, q; p != null && (q = p.prev) != null; p = q)
+                if ((w = p.waiter) != null)
+                    first = w;
         }
-        return firstThread;
+        return first;
     }
 
     /**
@@ -1003,7 +792,7 @@
         if (thread == null)
             throw new NullPointerException();
         for (Node p = tail; p != null; p = p.prev)
-            if (p.thread == thread)
+            if (p.waiter == thread)
                 return true;
         return false;
     }
@@ -1019,10 +808,8 @@
      */
     final boolean apparentlyFirstQueuedIsExclusive() {
         Node h, s;
-        return (h = head) != null &&
-            (s = h.next)  != null &&
-            !s.isShared()         &&
-            s.thread != null;
+        return (h = head) != null && (s = h.next)  != null &&
+            !(s instanceof SharedNode) && s.waiter != null;
     }
 
     /**
@@ -1052,7 +839,7 @@
      * synchronizer might look like this:
      *
      * <pre> {@code
-     * protected boolean tryAcquire(int arg) {
+     * protected boolean tryAcquire(long arg) {
      *   if (isHeldExclusively()) {
      *     // A reentrant acquire; increment hold count
      *     return true;
@@ -1069,19 +856,12 @@
      * @since 1.7
      */
     public final boolean hasQueuedPredecessors() {
-        Node h, s;
-        if ((h = head) != null) {
-            if ((s = h.next) == null || s.waitStatus > 0) {
-                s = null; // traverse in case of concurrent cancellation
-                for (Node p = tail; p != h && p != null; p = p.prev) {
-                    if (p.waitStatus <= 0)
-                        s = p;
-                }
-            }
-            if (s != null && s.thread != Thread.currentThread())
-                return true;
-        }
-        return false;
+        Thread first = null; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null))
+            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
+        return first != null && first != Thread.currentThread();
     }
 
     // Instrumentation and monitoring methods
@@ -1098,7 +878,7 @@
     public final int getQueueLength() {
         int n = 0;
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.thread != null)
+            if (p.waiter != null)
                 ++n;
         }
         return n;
@@ -1118,7 +898,7 @@
     public final Collection<Thread> getQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            Thread t = p.thread;
+            Thread t = p.waiter;
             if (t != null)
                 list.add(t);
         }
@@ -1136,8 +916,8 @@
     public final Collection<Thread> getExclusiveQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (!p.isShared()) {
-                Thread t = p.thread;
+            if (!(p instanceof SharedNode)) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1156,8 +936,8 @@
     public final Collection<Thread> getSharedQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.isShared()) {
-                Thread t = p.thread;
+            if (p instanceof SharedNode) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1180,117 +960,6 @@
             + (hasQueuedThreads() ? "non" : "") + "empty queue]";
     }
 
-
-    // Internal support methods for Conditions
-
-    /**
-     * Returns true if a node, always one that was initially placed on
-     * a condition queue, is now waiting to reacquire on sync queue.
-     * @param node the node
-     * @return true if is reacquiring
-     */
-    final boolean isOnSyncQueue(Node node) {
-        if (node.waitStatus == Node.CONDITION || node.prev == null)
-            return false;
-        if (node.next != null) // If has successor, it must be on queue
-            return true;
-        /*
-         * node.prev can be non-null, but not yet on queue because
-         * the CAS to place it on queue can fail. So we have to
-         * traverse from tail to make sure it actually made it.  It
-         * will always be near the tail in calls to this method, and
-         * unless the CAS failed (which is unlikely), it will be
-         * there, so we hardly ever traverse much.
-         */
-        return findNodeFromTail(node);
-    }
-
-    /**
-     * Returns true if node is on sync queue by searching backwards from tail.
-     * Called only when needed by isOnSyncQueue.
-     * @return true if present
-     */
-    private boolean findNodeFromTail(Node node) {
-        // We check for node first, since it's likely to be at or near tail.
-        // tail is known to be non-null, so we could re-order to "save"
-        // one null check, but we leave it this way to help the VM.
-        for (Node p = tail;;) {
-            if (p == node)
-                return true;
-            if (p == null)
-                return false;
-            p = p.prev;
-        }
-    }
-
-    /**
-     * Transfers a node from a condition queue onto sync queue.
-     * Returns true if successful.
-     * @param node the node
-     * @return true if successfully transferred (else the node was
-     * cancelled before signal)
-     */
-    final boolean transferForSignal(Node node) {
-        /*
-         * If cannot change waitStatus, the node has been cancelled.
-         */
-        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
-            return false;
-
-        /*
-         * Splice onto queue and try to set waitStatus of predecessor to
-         * indicate that thread is (probably) waiting. If cancelled or
-         * attempt to set waitStatus fails, wake up to resync (in which
-         * case the waitStatus can be transiently and harmlessly wrong).
-         */
-        Node p = enq(node);
-        int ws = p.waitStatus;
-        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
-            LockSupport.unpark(node.thread);
-        return true;
-    }
-
-    /**
-     * Transfers node, if necessary, to sync queue after a cancelled wait.
-     * Returns true if thread was cancelled before being signalled.
-     *
-     * @param node the node
-     * @return true if cancelled before the node was signalled
-     */
-    final boolean transferAfterCancelledWait(Node node) {
-        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
-            enq(node);
-            return true;
-        }
-        /*
-         * If we lost out to a signal(), then we can't proceed
-         * until it finishes its enq().  Cancelling during an
-         * incomplete transfer is both rare and transient, so just
-         * spin.
-         */
-        while (!isOnSyncQueue(node))
-            Thread.yield();
-        return false;
-    }
-
-    /**
-     * Invokes release with current state value; returns saved state.
-     * Cancels node and throws exception on failure.
-     * @param node the condition node for this wait
-     * @return previous sync state
-     */
-    final long fullyRelease(Node node) {
-        try {
-            long savedState = getState();
-            if (release(savedState))
-                return savedState;
-            throw new IllegalMonitorStateException();
-        } catch (Throwable t) {
-            node.waitStatus = Node.CANCELLED;
-            throw t;
-        }
-    }
-
     // Instrumentation methods for conditions
 
     /**
@@ -1384,112 +1053,38 @@
      *
      * <p>This class is Serializable, but all fields are transient,
      * so deserialized conditions have no waiters.
-     *
-     * @since 1.6
      */
     public class ConditionObject implements Condition, java.io.Serializable {
         private static final long serialVersionUID = 1173984872572414699L;
         /** First node of condition queue. */
-        private transient Node firstWaiter;
+        private transient ConditionNode firstWaiter;
         /** Last node of condition queue. */
-        private transient Node lastWaiter;
+        private transient ConditionNode lastWaiter;
 
         /**
          * Creates a new {@code ConditionObject} instance.
          */
         public ConditionObject() { }
 
-        // Internal methods
-
-        /**
-         * Adds a new waiter to wait queue.
-         * @return its new wait node
-         */
-        private Node addConditionWaiter() {
-            if (!isHeldExclusively())
-                throw new IllegalMonitorStateException();
-            Node t = lastWaiter;
-            // If lastWaiter is cancelled, clean out.
-            if (t != null && t.waitStatus != Node.CONDITION) {
-                unlinkCancelledWaiters();
-                t = lastWaiter;
-            }
-
-            Node node = new Node(Node.CONDITION);
-
-            if (t == null)
-                firstWaiter = node;
-            else
-                t.nextWaiter = node;
-            lastWaiter = node;
-            return node;
-        }
-
-        /**
-         * Removes and transfers nodes until hit non-cancelled one or
-         * null. Split out from signal in part to encourage compilers
-         * to inline the case of no waiters.
-         * @param first (non-null) the first node on condition queue
-         */
-        private void doSignal(Node first) {
-            do {
-                if ( (firstWaiter = first.nextWaiter) == null)
-                    lastWaiter = null;
-                first.nextWaiter = null;
-            } while (!transferForSignal(first) &&
-                     (first = firstWaiter) != null);
-        }
+        // Signalling methods
 
         /**
-         * Removes and transfers all nodes.
-         * @param first (non-null) the first node on condition queue
+         * Removes and transfers one or all waiters to sync queue.
          */
-        private void doSignalAll(Node first) {
-            lastWaiter = firstWaiter = null;
-            do {
-                Node next = first.nextWaiter;
-                first.nextWaiter = null;
-                transferForSignal(first);
+        private void doSignal(ConditionNode first, boolean all) {
+            while (first != null) {
+                ConditionNode next = first.nextWaiter;
+                if ((firstWaiter = next) == null)
+                    lastWaiter = null;
+                if ((first.getAndUnsetStatus(COND) & COND) != 0) {
+                    enqueue(first);
+                    if (!all)
+                        break;
+                }
                 first = next;
-            } while (first != null);
-        }
-
-        /**
-         * Unlinks cancelled waiter nodes from condition queue.
-         * Called only while holding lock. This is called when
-         * cancellation occurred during condition wait, and upon
-         * insertion of a new waiter when lastWaiter is seen to have
-         * been cancelled. This method is needed to avoid garbage
-         * retention in the absence of signals. So even though it may
-         * require a full traversal, it comes into play only when
-         * timeouts or cancellations occur in the absence of
-         * signals. It traverses all nodes rather than stopping at a
-         * particular target to unlink all pointers to garbage nodes
-         * without requiring many re-traversals during cancellation
-         * storms.
-         */
-        private void unlinkCancelledWaiters() {
-            Node t = firstWaiter;
-            Node trail = null;
-            while (t != null) {
-                Node next = t.nextWaiter;
-                if (t.waitStatus != Node.CONDITION) {
-                    t.nextWaiter = null;
-                    if (trail == null)
-                        firstWaiter = next;
-                    else
-                        trail.nextWaiter = next;
-                    if (next == null)
-                        lastWaiter = trail;
-                }
-                else
-                    trail = t;
-                t = next;
             }
         }
 
-        // public methods
-
         /**
          * Moves the longest-waiting thread, if one exists, from the
          * wait queue for this condition to the wait queue for the
@@ -1499,11 +1094,11 @@
          *         returns {@code false}
          */
         public final void signal() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignal(first);
+                doSignal(first, false);
         }
 
         /**
@@ -1514,11 +1109,72 @@
          *         returns {@code false}
          */
         public final void signalAll() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignalAll(first);
+                doSignal(first, true);
+        }
+
+        // Waiting methods
+
+        /**
+         * Adds node to condition list and releases lock.
+         *
+         * @param node the node
+         * @return savedState to reacquire after wait
+         */
+        private long enableWait(ConditionNode node) {
+            if (isHeldExclusively()) {
+                node.waiter = Thread.currentThread();
+                node.setStatusRelaxed(COND | WAITING);
+                ConditionNode last = lastWaiter;
+                if (last == null)
+                    firstWaiter = node;
+                else
+                    last.nextWaiter = node;
+                lastWaiter = node;
+                long savedState = getState();
+                if (release(savedState))
+                    return savedState;
+            }
+            node.status = CANCELLED; // lock not held or inconsistent
+            throw new IllegalMonitorStateException();
+        }
+
+        /**
+         * Returns true if a node that was initially placed on a condition
+         * queue is now ready to reacquire on sync queue.
+         * @param node the node
+         * @return true if is reacquiring
+         */
+        private boolean canReacquire(ConditionNode node) {
+            // check links, not status to avoid enqueue race
+            return node != null && node.prev != null && isEnqueued(node);
+        }
+
+        /**
+         * Unlinks the given node and other non-waiting nodes from
+         * condition queue unless already unlinked.
+         */
+        private void unlinkCancelledWaiters(ConditionNode node) {
+            if (node == null || node.nextWaiter != null || node == lastWaiter) {
+                ConditionNode w = firstWaiter, trail = null;
+                while (w != null) {
+                    ConditionNode next = w.nextWaiter;
+                    if ((w.status & COND) == 0) {
+                        w.nextWaiter = null;
+                        if (trail == null)
+                            firstWaiter = next;
+                        else
+                            trail.nextWaiter = next;
+                        if (next == null)
+                            lastWaiter = trail;
+                    } else
+                        trail = w;
+                    w = next;
+                }
+            }
         }
 
         /**
@@ -1533,51 +1189,27 @@
          * </ol>
          */
         public final void awaitUninterruptibly() {
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
             boolean interrupted = false;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
+            while (!canReacquire(node)) {
                 if (Thread.interrupted())
                     interrupted = true;
+                else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) || interrupted)
-                selfInterrupt();
-        }
-
-        /*
-         * For interruptible waits, we need to track whether to throw
-         * InterruptedException, if interrupted while blocked on
-         * condition, versus reinterrupt current thread, if
-         * interrupted while blocked waiting to re-acquire.
-         */
-
-        /** Mode meaning to reinterrupt on exit from wait */
-        private static final int REINTERRUPT =  1;
-        /** Mode meaning to throw InterruptedException on exit from wait */
-        private static final int THROW_IE    = -1;
-
-        /**
-         * Checks for interrupt, returning THROW_IE if interrupted
-         * before signalled, REINTERRUPT if after signalled, or
-         * 0 if not interrupted.
-         */
-        private int checkInterruptWhileWaiting(Node node) {
-            return Thread.interrupted() ?
-                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
-                0;
-        }
-
-        /**
-         * Throws InterruptedException, reinterrupts current thread, or
-         * does nothing, depending on mode.
-         */
-        private void reportInterruptAfterWait(int interruptMode)
-            throws InterruptedException {
-            if (interruptMode == THROW_IE)
-                throw new InterruptedException();
-            else if (interruptMode == REINTERRUPT)
-                selfInterrupt();
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted)
+                Thread.currentThread().interrupt();
         }
 
         /**
@@ -1596,20 +1228,33 @@
         public final void await() throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
+            boolean interrupted = false, cancelled = false;
+            while (!canReacquire(node)) {
+                if (interrupted |= Thread.interrupted()) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;              // else interrupted after signal
+                } else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null) // clean up if cancelled
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted) {
+                if (cancelled) {
+                    unlinkCancelledWaiters(node);
+                    throw new InterruptedException();
+                }
+                Thread.currentThread().interrupt();
+            }
         }
 
         /**
@@ -1629,32 +1274,29 @@
                 throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // awaitNanos(0) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            long initialNanos = nanosTimeout;
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
             long remaining = deadline - System.nanoTime(); // avoid overflow
-            return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+            return (remaining <= nanosTimeout) ? remaining : Long.MIN_VALUE;
         }
 
         /**
@@ -1676,26 +1318,26 @@
             long abstime = deadline.getTime();
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (System.currentTimeMillis() >= abstime) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                LockSupport.parkUntil(this, abstime);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    System.currentTimeMillis() >= abstime) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkUntil(this, abstime);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         /**
@@ -1717,31 +1359,28 @@
             long nanosTimeout = unit.toNanos(time);
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // await(0, unit) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         //  support for instrumentation
@@ -1767,8 +1406,8 @@
         protected final boolean hasWaiters() {
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     return true;
             }
             return false;
@@ -1787,8 +1426,8 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             int n = 0;
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     ++n;
             }
             return n;
@@ -1807,9 +1446,9 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             ArrayList<Thread> list = new ArrayList<>();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION) {
-                    Thread t = w.thread;
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0) {
+                    Thread t = w.waiter;
                     if (t != null)
                         list.add(t);
                 }
@@ -1818,39 +1457,16 @@
         }
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATE;
-    private static final VarHandle HEAD;
-    private static final VarHandle TAIL;
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "tail");
 
     static {
-        try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "state", long.class);
-            HEAD = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "head", Node.class);
-            TAIL = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "tail", Node.class);
-        } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
-        }
-
-        // Reduce the risk of rare disastrous classloading in first call to
-        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
         Class<?> ensureLoaded = LockSupport.class;
     }
-
-    /**
-     * Initializes head and tail fields on first contention.
-     */
-    private final void initializeSyncQueue() {
-        Node h;
-        if (HEAD.compareAndSet(this, null, (h = new Node())))
-            tail = h;
-    }
-
-    /**
-     * CASes tail field.
-     */
-    private final boolean compareAndSetTail(Node expect, Node update) {
-        return TAIL.compareAndSet(this, expect, update);
-    }
 }
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Sun Sep 15 13:41:19 2019 +0200
@@ -35,12 +35,12 @@
 
 package java.util.concurrent.locks;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ForkJoinPool;
+import jdk.internal.misc.Unsafe;
 
 /**
  * Provides a framework for implementing blocking locks and related
@@ -312,265 +312,208 @@
      */
     protected AbstractQueuedSynchronizer() { }
 
-    /**
-     * Wait queue node class.
+    /*
+     * Overview.
      *
-     * <p>The wait queue is a variant of a "CLH" (Craig, Landin, and
+     * The wait queue is a variant of a "CLH" (Craig, Landin, and
      * Hagersten) lock queue. CLH locks are normally used for
-     * spinlocks.  We instead use them for blocking synchronizers, but
-     * use the same basic tactic of holding some of the control
-     * information about a thread in the predecessor of its node.  A
-     * "status" field in each node keeps track of whether a thread
-     * should block.  A node is signalled when its predecessor
-     * releases.  Each node of the queue otherwise serves as a
-     * specific-notification-style monitor holding a single waiting
-     * thread. The status field does NOT control whether threads are
-     * granted locks etc though.  A thread may try to acquire if it is
-     * first in the queue. But being first does not guarantee success;
-     * it only gives the right to contend.  So the currently released
-     * contender thread may need to rewait.
+     * spinlocks.  We instead use them for blocking synchronizers by
+     * including explicit ("prev" and "next") links plus a "status"
+     * field that allow nodes to signal successors when releasing
+     * locks, and handle cancellation due to interrupts and timeouts.
+     * The status field includes bits that track whether a thread
+     * needs a signal (using LockSupport.unpark). Despite these
+     * additions, we maintain most CLH locality properties.
+     *
+     * To enqueue into a CLH lock, you atomically splice it in as new
+     * tail. To dequeue, you set the head field, so the next eligible
+     * waiter becomes first.
      *
-     * <p>To enqueue into a CLH lock, you atomically splice it in as new
-     * tail. To dequeue, you just set the head field.
-     * <pre>
-     *      +------+  prev +-----+       +-----+
-     * head |      | <---- |     | <---- |     |  tail
-     *      +------+       +-----+       +-----+
-     * </pre>
+     *  +------+  prev +-------+       +------+
+     *  | head | <---- | first | <---- | tail |
+     *  +------+       +-------+       +------+
+     *
+     * Insertion into a CLH queue requires only a single atomic
+     * operation on "tail", so there is a simple point of demarcation
+     * from unqueued to queued. The "next" link of the predecessor is
+     * set by the enqueuing thread after successful CAS. Even though
+     * non-atomic, this suffices to ensure that any blocked thread is
+     * signalled by a predecessor when eligible (although in the case
+     * of cancellation, possibly with the assistance of a signal in
+     * method cleanQueue). Signalling is based in part on a
+     * Dekker-like scheme in which the to-be waiting thread indicates
+     * WAITING status, then retries acquiring, and then rechecks
+     * status before blocking. The signaller atomically clears WAITING
+     * status when unparking.
      *
-     * <p>Insertion into a CLH queue requires only a single atomic
-     * operation on "tail", so there is a simple atomic point of
-     * demarcation from unqueued to queued. Similarly, dequeuing
-     * involves only updating the "head". However, it takes a bit
-     * more work for nodes to determine who their successors are,
-     * in part to deal with possible cancellation due to timeouts
-     * and interrupts.
-     *
-     * <p>The "prev" links (not used in original CLH locks), are mainly
-     * needed to handle cancellation. If a node is cancelled, its
-     * successor is (normally) relinked to a non-cancelled
-     * predecessor. For explanation of similar mechanics in the case
-     * of spin locks, see the papers by Scott and Scherer at
-     * http://www.cs.rochester.edu/u/scott/synchronization/
+     * Dequeuing on acquire involves detaching (nulling) a node's
+     * "prev" node and then updating the "head". Other threads check
+     * if a node is or was dequeued by checking "prev" rather than
+     * head. We enforce the nulling then setting order by spin-waiting
+     * if necessary. Because of this, the lock algorithm is not itself
+     * strictly "lock-free" because an acquiring thread may need to
+     * wait for a previous acquire to make progress. When used with
+     * exclusive locks, such progress is required anyway. However
+     * Shared mode may (uncommonly) require a spin-wait before
+     * setting head field to ensure proper propagation. (Historical
+     * note: This allows some simplifications and efficiencies
+     * compared to previous versions of this class.)
      *
-     * <p>We also use "next" links to implement blocking mechanics.
-     * The thread id for each node is kept in its own node, so a
-     * predecessor signals the next node to wake up by traversing
-     * next link to determine which thread it is.  Determination of
-     * successor must avoid races with newly queued nodes to set
-     * the "next" fields of their predecessors.  This is solved
-     * when necessary by checking backwards from the atomically
-     * updated "tail" when a node's successor appears to be null.
-     * (Or, said differently, the next-links are an optimization
-     * so that we don't usually need a backward scan.)
+     * A node's predecessor can change due to cancellation while it is
+     * waiting, until the node is first in queue, at which point it
+     * cannot change. The acquire methods cope with this by rechecking
+     * "prev" before waiting. The prev and next fields are modified
+     * only via CAS by cancelled nodes in method cleanQueue. The
+     * unsplice strategy is reminiscent of Michael-Scott queues in
+     * that after a successful CAS to prev field, other threads help
+     * fix next fields.  Because cancellation often occurs in bunches
+     * that complicate decisions about necessary signals, each call to
+     * cleanQueue traverses the queue until a clean sweep. Nodes that
+     * become relinked as first are unconditionally unparked
+     * (sometimes unnecessarily, but those cases are not worth
+     * avoiding).
      *
-     * <p>Cancellation introduces some conservatism to the basic
-     * algorithms.  Since we must poll for cancellation of other
-     * nodes, we can miss noticing whether a cancelled node is
-     * ahead or behind us. This is dealt with by always unparking
-     * successors upon cancellation, allowing them to stabilize on
-     * a new predecessor, unless we can identify an uncancelled
-     * predecessor who will carry this responsibility.
+     * A thread may try to acquire if it is first (frontmost) in the
+     * queue, and sometimes before.  Being first does not guarantee
+     * success; it only gives the right to contend. We balance
+     * throughput, overhead, and fairness by allowing incoming threads
+     * to "barge" and acquire the synchronizer while in the process of
+     * enqueuing, in which case an awakened first thread may need to
+     * rewait.  To counteract possible repeated unlucky rewaits, we
+     * exponentially increase retries (up to 256) to acquire each time
+     * a thread is unparked. Except in this case, AQS locks do not
+     * spin; they instead interleave attempts to acquire with
+     * bookkeeping steps. (Users who want spinlocks can use
+     * tryAcquire.)
      *
-     * <p>CLH queues need a dummy header node to get started. But
+     * To improve garbage collectibility, fields of nodes not yet on
+     * list are null. (It is not rare to create and then throw away a
+     * node without using it.) Fields of nodes coming off the list are
+     * nulled out as soon as possible. This accentuates the challenge
+     * of externally determining the first waiting thread (as in
+     * method getFirstQueuedThread). This sometimes requires the
+     * fallback of traversing backwards from the atomically updated
+     * "tail" when fields appear null. (This is never needed in the
+     * process of signalling though.)
+     *
+     * CLH queues need a dummy header node to get started. But
      * we don't create them on construction, because it would be wasted
      * effort if there is never contention. Instead, the node
      * is constructed and head and tail pointers are set upon first
      * contention.
      *
-     * <p>Threads waiting on Conditions use the same nodes, but
-     * use an additional link. Conditions only need to link nodes
-     * in simple (non-concurrent) linked queues because they are
-     * only accessed when exclusively held.  Upon await, a node is
-     * inserted into a condition queue.  Upon signal, the node is
-     * transferred to the main queue.  A special value of status
-     * field is used to mark which queue a node is on.
+     * Shared mode operations differ from Exclusive in that an acquire
+     * signals the next waiter to try to acquire if it is also
+     * Shared. The tryAcquireShared API allows users to indicate the
+     * degree of propagation, but in most applications, it is more
+     * efficient to ignore this, allowing the successor to try
+     * acquiring in any case.
+     *
+     * Threads waiting on Conditions use nodes with an additional
+     * link to maintain the (FIFO) list of conditions. Conditions only
+     * need to link nodes in simple (non-concurrent) linked queues
+     * because they are only accessed when exclusively held.  Upon
+     * await, a node is inserted into a condition queue.  Upon signal,
+     * the node is enqueued on the main queue.  A special status field
+     * value is used to track and atomically trigger this.
      *
-     * <p>Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
+     * Accesses to fields head, tail, and state use full Volatile
+     * mode, along with CAS. Node fields status, prev and next also do
+     * so while threads may be signallable, but sometimes use weaker
+     * modes otherwise. Accesses to field "waiter" (the thread to be
+     * signalled) are always sandwiched between other atomic accesses
+     * so are used in Plain mode. We use jdk.internal Unsafe versions
+     * of atomic access methods rather than VarHandles to avoid
+     * potential VM bootstrap issues.
+     *
+     * Most of the above is performed by primary internal method
+     * acquire, that is invoked in some way by all exported acquire
+     * methods.  (It is usually easy for compilers to optimize
+     * call-site specializations when heavily used.)
+     *
+     * There are several arbitrary decisions about when and how to
+     * check interrupts in both acquire and await before and/or after
+     * blocking. The decisions are less arbitrary in implementation
+     * updates because some users appear to rely on original behaviors
+     * in ways that are racy and so (rarely) wrong in general but hard
+     * to justify changing.
+     *
+     * Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
      * Scherer and Michael Scott, along with members of JSR-166
      * expert group, for helpful ideas, discussions, and critiques
      * on the design of this class.
      */
-    static final class Node {
-        /** Marker to indicate a node is waiting in shared mode */
-        static final Node SHARED = new Node();
-        /** Marker to indicate a node is waiting in exclusive mode */
-        static final Node EXCLUSIVE = null;
+
+    // Node status bits, also used as argument and return values
+    static final int WAITING   = 1;          // must be 1
+    static final int CANCELLED = 0x80000000; // must be negative
+    static final int COND      = 2;          // in a condition wait
 
-        /** waitStatus value to indicate thread has cancelled. */
-        static final int CANCELLED =  1;
-        /** waitStatus value to indicate successor's thread needs unparking. */
-        static final int SIGNAL    = -1;
-        /** waitStatus value to indicate thread is waiting on condition. */
-        static final int CONDITION = -2;
-        /**
-         * waitStatus value to indicate the next acquireShared should
-         * unconditionally propagate.
-         */
-        static final int PROPAGATE = -3;
+    /** CLH Nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
 
-        /**
-         * Status field, taking on only the values:
-         *   SIGNAL:     The successor of this node is (or will soon be)
-         *               blocked (via park), so the current node must
-         *               unpark its successor when it releases or
-         *               cancels. To avoid races, acquire methods must
-         *               first indicate they need a signal,
-         *               then retry the atomic acquire, and then,
-         *               on failure, block.
-         *   CANCELLED:  This node is cancelled due to timeout or interrupt.
-         *               Nodes never leave this state. In particular,
-         *               a thread with cancelled node never again blocks.
-         *   CONDITION:  This node is currently on a condition queue.
-         *               It will not be used as a sync queue node
-         *               until transferred, at which time the status
-         *               will be set to 0. (Use of this value here has
-         *               nothing to do with the other uses of the
-         *               field, but simplifies mechanics.)
-         *   PROPAGATE:  A releaseShared should be propagated to other
-         *               nodes. This is set (for head node only) in
-         *               doReleaseShared to ensure propagation
-         *               continues, even if other operations have
-         *               since intervened.
-         *   0:          None of the above
-         *
-         * The values are arranged numerically to simplify use.
-         * Non-negative values mean that a node doesn't need to
-         * signal. So, most code doesn't need to check for particular
-         * values, just for sign.
-         *
-         * The field is initialized to 0 for normal sync nodes, and
-         * CONDITION for condition nodes.  It is modified using CAS
-         * (or when possible, unconditional volatile writes).
-         */
-        volatile int waitStatus;
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
 
-        /**
-         * Link to predecessor node that current node/thread relies on
-         * for checking waitStatus. Assigned during enqueuing, and nulled
-         * out (for sake of GC) only upon dequeuing.  Also, upon
-         * cancellation of a predecessor, we short-circuit while
-         * finding a non-cancelled one, which will always exist
-         * because the head node is never cancelled: A node becomes
-         * head only as a result of successful acquire. A
-         * cancelled thread never succeeds in acquiring, and a thread only
-         * cancels itself, not any other node.
-         */
-        volatile Node prev;
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
 
-        /**
-         * Link to the successor node that the current node/thread
-         * unparks upon release. Assigned during enqueuing, adjusted
-         * when bypassing cancelled predecessors, and nulled out (for
-         * sake of GC) when dequeued.  The enq operation does not
-         * assign next field of a predecessor until after attachment,
-         * so seeing a null next field does not necessarily mean that
-         * node is at end of queue. However, if a next field appears
-         * to be null, we can scan prev's from the tail to
-         * double-check.  The next field of cancelled nodes is set to
-         * point to the node itself instead of null, to make life
-         * easier for isOnSyncQueue.
-         */
-        volatile Node next;
+    // Concrete classes tagged by type
+    static final class ExclusiveNode extends Node { }
+    static final class SharedNode extends Node { }
+
+    static final class ConditionNode extends Node
+        implements ForkJoinPool.ManagedBlocker {
+        ConditionNode nextWaiter;            // link to next waiting node
 
         /**
-         * The thread that enqueued this node.  Initialized on
-         * construction and nulled out after use.
-         */
-        volatile Thread thread;
-
-        /**
-         * Link to next node waiting on condition, or the special
-         * value SHARED.  Because condition queues are accessed only
-         * when holding in exclusive mode, we just need a simple
-         * linked queue to hold nodes while they are waiting on
-         * conditions. They are then transferred to the queue to
-         * re-acquire. And because conditions can only be exclusive,
-         * we save a field by using special value to indicate shared
-         * mode.
+         * Allows Conditions to be used in ForkJoinPools without
+         * risking fixed pool exhaustion. This is usable only for
+         * untimed Condition waits, not timed versions.
          */
-        Node nextWaiter;
-
-        /**
-         * Returns true if node is waiting in shared mode.
-         */
-        final boolean isShared() {
-            return nextWaiter == SHARED;
-        }
-
-        /**
-         * Returns previous node, or throws NullPointerException if null.
-         * Use when predecessor cannot be null.  The null check could
-         * be elided, but is present to help the VM.
-         *
-         * @return the predecessor of this node
-         */
-        final Node predecessor() {
-            Node p = prev;
-            if (p == null)
-                throw new NullPointerException();
-            else
-                return p;
+        public final boolean isReleasable() {
+            return status <= 1 || Thread.currentThread().isInterrupted();
         }
 
-        /** Establishes initial head or SHARED marker. */
-        Node() {}
-
-        /** Constructor used by addWaiter. */
-        Node(Node nextWaiter) {
-            this.nextWaiter = nextWaiter;
-            THREAD.set(this, Thread.currentThread());
-        }
-
-        /** Constructor used by addConditionWaiter. */
-        Node(int waitStatus) {
-            WAITSTATUS.set(this, waitStatus);
-            THREAD.set(this, Thread.currentThread());
-        }
-
-        /** CASes waitStatus field. */
-        final boolean compareAndSetWaitStatus(int expect, int update) {
-            return WAITSTATUS.compareAndSet(this, expect, update);
-        }
-
-        /** CASes next field. */
-        final boolean compareAndSetNext(Node expect, Node update) {
-            return NEXT.compareAndSet(this, expect, update);
-        }
-
-        final void setPrevRelaxed(Node p) {
-            PREV.set(this, p);
-        }
-
-        // VarHandle mechanics
-        private static final VarHandle NEXT;
-        private static final VarHandle PREV;
-        private static final VarHandle THREAD;
-        private static final VarHandle WAITSTATUS;
-        static {
-            try {
-                MethodHandles.Lookup l = MethodHandles.lookup();
-                NEXT = l.findVarHandle(Node.class, "next", Node.class);
-                PREV = l.findVarHandle(Node.class, "prev", Node.class);
-                THREAD = l.findVarHandle(Node.class, "thread", Thread.class);
-                WAITSTATUS = l.findVarHandle(Node.class, "waitStatus", int.class);
-            } catch (ReflectiveOperationException e) {
-                throw new ExceptionInInitializerError(e);
-            }
+        public final boolean block() {
+            while (!isReleasable()) LockSupport.park(this);
+            return true;
         }
     }
 
     /**
-     * Head of the wait queue, lazily initialized.  Except for
-     * initialization, it is modified only via method setHead.  Note:
-     * If head exists, its waitStatus is guaranteed not to be
-     * CANCELLED.
+     * Head of the wait queue, lazily initialized.
      */
     private transient volatile Node head;
 
     /**
-     * Tail of the wait queue, lazily initialized.  Modified only via
-     * method enq to add new wait node.
+     * Tail of the wait queue. After initialization, modified only via casTail.
      */
     private transient volatile Node tail;
 
@@ -609,481 +552,235 @@
      *         value was not equal to the expected value.
      */
     protected final boolean compareAndSetState(int expect, int update) {
-        return STATE.compareAndSet(this, expect, update);
+        return U.compareAndSetInt(this, STATE, expect, update);
     }
 
     // Queuing utilities
 
-    /**
-     * The number of nanoseconds for which it is faster to spin
-     * rather than to use timed park. A rough estimate suffices
-     * to improve responsiveness with very short timeouts.
-     */
-    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new ExclusiveNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
 
     /**
-     * Inserts node into queue, initializing if necessary. See picture above.
-     * @param node the node to insert
-     * @return node's predecessor
+     * Enqueues the node unless null. (Currently used only for
+     * ConditionNodes; other cases are interleaved with acquires.)
      */
-    private Node enq(Node node) {
-        for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return oldTail;
+    final void enqueue(Node node) {
+        if (node != null) {
+            for (;;) {
+                Node t = tail;
+                node.setPrevRelaxed(t);        // avoid unnecessary fence
+                if (t == null)                 // initialize
+                    tryInitializeHead();
+                else if (casTail(t, node)) {
+                    t.next = node;
+                    if (t.status < 0)          // wake up to clean link
+                        LockSupport.unpark(node.waiter);
+                    break;
                 }
-            } else {
-                initializeSyncQueue();
             }
         }
     }
 
+    /** Returns true if node is found in traversal from tail */
+    final boolean isEnqueued(Node node) {
+        for (Node t = tail; t != null; t = t.prev)
+            if (t == node)
+                return true;
+        return false;
+    }
+
     /**
-     * Creates and enqueues node for current thread and given mode.
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
+     */
+    private static void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /** Wakes up the given node if in shared mode */
+    private static void signalNextIfShared(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null &&
+            (s instanceof SharedNode) && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /**
+     * Main acquire method, invoked by all exported acquire methods.
      *
-     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
-     * @return the new node
+     * @param node null unless a reacquiring Condition
+     * @param arg the acquire argument
+     * @param shared true if shared mode else exclusive
+     * @param interruptible if abort and return negative on interrupt
+     * @param timed if true use timed waits
+     * @param time if timed, the System.nanoTime value to timeout
+     * @return positive if acquired, 0 if timed out, negative if interrupted
      */
-    private Node addWaiter(Node mode) {
-        Node node = new Node(mode);
+    final int acquire(Node node, int arg, boolean shared,
+                      boolean interruptible, boolean timed, long time) {
+        Thread current = Thread.currentThread();
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        Node pred = null;                // predecessor of node when enqueued
+
+        /*
+         * Repeatedly:
+         *  Check if node now first
+         *    if so, ensure head stable, else ensure valid predecessor
+         *  if node is first or not yet enqueued, try acquiring
+         *  else if node not yet created, create it
+         *  else if not yet enqueued, try once to enqueue
+         *  else if woken from park, retry (up to postSpins times)
+         *  else if WAITING status not set, set and retry
+         *  else park and clear WAITING status, and check cancellation
+         */
 
         for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return node;
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
+            }
+            if (first || pred == null) {
+                boolean acquired;
+                try {
+                    if (shared)
+                        acquired = (tryAcquireShared(arg) >= 0);
+                    else
+                        acquired = tryAcquire(arg);
+                } catch (Throwable ex) {
+                    cancelAcquire(node, interrupted, false);
+                    throw ex;
+                }
+                if (acquired) {
+                    if (first) {
+                        node.prev = null;
+                        head = node;
+                        pred.next = null;
+                        node.waiter = null;
+                        if (shared)
+                            signalNextIfShared(node);
+                        if (interrupted)
+                            current.interrupt();
+                    }
+                    return 1;
                 }
+            }
+            if (node == null) {                 // allocate; retry before enqueue
+                if (shared)
+                    node = new SharedNode();
+                else
+                    node = new ExclusiveNode();
+            } else if (pred == null) {          // try to enqueue
+                node.waiter = current;
+                Node t = tail;
+                node.setPrevRelaxed(t);         // avoid unnecessary fence
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {
+                --spins;                        // reduce unfairness on rewaits
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                node.status = WAITING;          // enable signal and recheck
             } else {
-                initializeSyncQueue();
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted, interruptible);
+    }
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found. Unparks nodes that may have been
+     * relinked to be next eligible acquirer.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
             }
         }
     }
 
     /**
-     * Sets head of queue to be node, thus dequeuing. Called only by
-     * acquire methods.  Also nulls out unused fields for sake of GC
-     * and to suppress unnecessary signals and traversals.
-     *
-     * @param node the node
-     */
-    private void setHead(Node node) {
-        head = node;
-        node.thread = null;
-        node.prev = null;
-    }
-
-    /**
-     * Wakes up node's successor, if one exists.
-     *
-     * @param node the node
-     */
-    private void unparkSuccessor(Node node) {
-        /*
-         * If status is negative (i.e., possibly needing signal) try
-         * to clear in anticipation of signalling.  It is OK if this
-         * fails or if status is changed by waiting thread.
-         */
-        int ws = node.waitStatus;
-        if (ws < 0)
-            node.compareAndSetWaitStatus(ws, 0);
-
-        /*
-         * Thread to unpark is held in successor, which is normally
-         * just the next node.  But if cancelled or apparently null,
-         * traverse backwards from tail to find the actual
-         * non-cancelled successor.
-         */
-        Node s = node.next;
-        if (s == null || s.waitStatus > 0) {
-            s = null;
-            for (Node p = tail; p != node && p != null; p = p.prev)
-                if (p.waitStatus <= 0)
-                    s = p;
-        }
-        if (s != null)
-            LockSupport.unpark(s.thread);
-    }
-
-    /**
-     * Release action for shared mode -- signals successor and ensures
-     * propagation. (Note: For exclusive mode, release just amounts
-     * to calling unparkSuccessor of head if it needs signal.)
-     */
-    private void doReleaseShared() {
-        /*
-         * Ensure that a release propagates, even if there are other
-         * in-progress acquires/releases.  This proceeds in the usual
-         * way of trying to unparkSuccessor of head if it needs
-         * signal. But if it does not, status is set to PROPAGATE to
-         * ensure that upon release, propagation continues.
-         * Additionally, we must loop in case a new node is added
-         * while we are doing this. Also, unlike other uses of
-         * unparkSuccessor, we need to know if CAS to reset status
-         * fails, if so rechecking.
-         */
-        for (;;) {
-            Node h = head;
-            if (h != null && h != tail) {
-                int ws = h.waitStatus;
-                if (ws == Node.SIGNAL) {
-                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
-                        continue;            // loop to recheck cases
-                    unparkSuccessor(h);
-                }
-                else if (ws == 0 &&
-                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
-                    continue;                // loop on failed CAS
-            }
-            if (h == head)                   // loop if head changed
-                break;
-        }
-    }
-
-    /**
-     * Sets head of queue, and checks if successor may be waiting
-     * in shared mode, if so propagating if either propagate > 0 or
-     * PROPAGATE status was set.
-     *
-     * @param node the node
-     * @param propagate the return value from a tryAcquireShared
-     */
-    private void setHeadAndPropagate(Node node, int propagate) {
-        Node h = head; // Record old head for check below
-        setHead(node);
-        /*
-         * Try to signal next queued node if:
-         *   Propagation was indicated by caller,
-         *     or was recorded (as h.waitStatus either before
-         *     or after setHead) by a previous operation
-         *     (note: this uses sign-check of waitStatus because
-         *      PROPAGATE status may transition to SIGNAL.)
-         * and
-         *   The next node is waiting in shared mode,
-         *     or we don't know, because it appears null
-         *
-         * The conservatism in both of these checks may cause
-         * unnecessary wake-ups, but only when there are multiple
-         * racing acquires/releases, so most need signals now or soon
-         * anyway.
-         */
-        if (propagate > 0 || h == null || h.waitStatus < 0 ||
-            (h = head) == null || h.waitStatus < 0) {
-            Node s = node.next;
-            if (s == null || s.isShared())
-                doReleaseShared();
-        }
-    }
-
-    // Utilities for various versions of acquire
-
-    /**
      * Cancels an ongoing attempt to acquire.
      *
-     * @param node the node
-     */
-    private void cancelAcquire(Node node) {
-        // Ignore if node doesn't exist
-        if (node == null)
-            return;
-
-        node.thread = null;
-
-        // Skip cancelled predecessors
-        Node pred = node.prev;
-        while (pred.waitStatus > 0)
-            node.prev = pred = pred.prev;
-
-        // predNext is the apparent node to unsplice. CASes below will
-        // fail if not, in which case, we lost race vs another cancel
-        // or signal, so no further action is necessary, although with
-        // a possibility that a cancelled node may transiently remain
-        // reachable.
-        Node predNext = pred.next;
-
-        // Can use unconditional write instead of CAS here.
-        // After this atomic step, other Nodes can skip past us.
-        // Before, we are free of interference from other threads.
-        node.waitStatus = Node.CANCELLED;
-
-        // If we are the tail, remove ourselves.
-        if (node == tail && compareAndSetTail(node, pred)) {
-            pred.compareAndSetNext(predNext, null);
-        } else {
-            // If successor needs signal, try to set pred's next-link
-            // so it will get one. Otherwise wake it up to propagate.
-            int ws;
-            if (pred != head &&
-                ((ws = pred.waitStatus) == Node.SIGNAL ||
-                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
-                pred.thread != null) {
-                Node next = node.next;
-                if (next != null && next.waitStatus <= 0)
-                    pred.compareAndSetNext(predNext, next);
-            } else {
-                unparkSuccessor(node);
-            }
-
-            node.next = node; // help GC
-        }
-    }
-
-    /**
-     * Checks and updates status for a node that failed to acquire.
-     * Returns true if thread should block. This is the main signal
-     * control in all acquire loops.  Requires that pred == node.prev.
-     *
-     * @param pred node's predecessor holding status
-     * @param node the node
-     * @return {@code true} if thread should block
-     */
-    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
-        int ws = pred.waitStatus;
-        if (ws == Node.SIGNAL)
-            /*
-             * This node has already set status asking a release
-             * to signal it, so it can safely park.
-             */
-            return true;
-        if (ws > 0) {
-            /*
-             * Predecessor was cancelled. Skip over predecessors and
-             * indicate retry.
-             */
-            do {
-                node.prev = pred = pred.prev;
-            } while (pred.waitStatus > 0);
-            pred.next = node;
-        } else {
-            /*
-             * waitStatus must be 0 or PROPAGATE.  Indicate that we
-             * need a signal, but don't park yet.  Caller will need to
-             * retry to make sure it cannot acquire before parking.
-             */
-            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
-        }
-        return false;
-    }
-
-    /**
-     * Convenience method to interrupt current thread.
-     */
-    static void selfInterrupt() {
-        Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Convenience method to park and then check if interrupted.
-     *
-     * @return {@code true} if interrupted
-     */
-    private final boolean parkAndCheckInterrupt() {
-        LockSupport.park(this);
-        return Thread.interrupted();
-    }
-
-    /*
-     * Various flavors of acquire, varying in exclusive/shared and
-     * control modes.  Each is mostly the same, but annoyingly
-     * different.  Only a little bit of factoring is possible due to
-     * interactions of exception mechanics (including ensuring that we
-     * cancel if tryAcquire throws exception) and other control, at
-     * least not without hurting performance too much.
-     */
-
-    /**
-     * Acquires in exclusive uninterruptible mode for thread already in
-     * queue. Used by condition wait methods as well as acquire.
-     *
-     * @param node the node
-     * @param arg the acquire argument
-     * @return {@code true} if interrupted while waiting
-     */
-    final boolean acquireQueued(final Node node, int arg) {
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return interrupted;
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            if (interrupted)
-                selfInterrupt();
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive interruptible mode.
-     * @param arg the acquire argument
+     * @param node the node (may be null if cancelled before enqueuing)
+     * @param interrupted true if thread interrupted
+     * @param interruptible if should report interruption vs reset
      */
-    private void doAcquireInterruptibly(int arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireNanos(int arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return true;
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
+    private int cancelAcquire(Node node, boolean interrupted,
+                              boolean interruptible) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            if (node.prev != null)
+                cleanQueue();
         }
-    }
-
-    /**
-     * Acquires in shared uninterruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireShared(int arg) {
-        final Node node = addWaiter(Node.SHARED);
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    int r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        } finally {
-            if (interrupted)
-                selfInterrupt();
+        if (interrupted) {
+            if (interruptible)
+                return CANCELLED;
+            else
+                Thread.currentThread().interrupt();
         }
-    }
-
-    /**
-     * Acquires in shared interruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireSharedInterruptibly(int arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    int r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in shared timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    int r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return true;
-                    }
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
+        return 0;
     }
 
     // Main exported methods
@@ -1236,9 +933,8 @@
      *        can represent anything you like.
      */
     public final void acquire(int arg) {
-        if (!tryAcquire(arg) &&
-            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
-            selfInterrupt();
+        if (!tryAcquire(arg))
+            acquire(null, arg, false, false, false, 0L);
     }
 
     /**
@@ -1256,11 +952,10 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireInterruptibly(int arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (!tryAcquire(arg) && acquire(null, arg, false, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (!tryAcquire(arg))
-            doAcquireInterruptibly(arg);
     }
 
     /**
@@ -1281,11 +976,20 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final boolean tryAcquireNanos(int arg, long nanosTimeout)
-            throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquire(arg) ||
-            doAcquireNanos(arg, nanosTimeout);
+        throws InterruptedException {
+        if (!Thread.interrupted()) {
+            if (tryAcquire(arg))
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, false, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -1300,9 +1004,7 @@
      */
     public final boolean release(int arg) {
         if (tryRelease(arg)) {
-            Node h = head;
-            if (h != null && h.waitStatus != 0)
-                unparkSuccessor(h);
+            signalNext(head);
             return true;
         }
         return false;
@@ -1321,7 +1023,7 @@
      */
     public final void acquireShared(int arg) {
         if (tryAcquireShared(arg) < 0)
-            doAcquireShared(arg);
+            acquire(null, arg, true, false, false, 0L);
     }
 
     /**
@@ -1338,11 +1040,11 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireSharedInterruptibly(int arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (tryAcquireShared(arg) < 0 &&
+             acquire(null, arg, true, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (tryAcquireShared(arg) < 0)
-            doAcquireSharedInterruptibly(arg);
     }
 
     /**
@@ -1363,10 +1065,19 @@
      */
     public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
             throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquireShared(arg) >= 0 ||
-            doAcquireSharedNanos(arg, nanosTimeout);
+        if (!Thread.interrupted()) {
+            if (tryAcquireShared(arg) >= 0)
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, true, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -1380,7 +1091,7 @@
      */
     public final boolean releaseShared(int arg) {
         if (tryReleaseShared(arg)) {
-            doReleaseShared();
+            signalNext(head);
             return true;
         }
         return false;
@@ -1398,7 +1109,7 @@
      */
     public final boolean hasQueuedThreads() {
         for (Node p = tail, h = head; p != h && p != null; p = p.prev)
-            if (p.waitStatus <= 0)
+            if (p.status >= 0)
                 return true;
         return false;
     }
@@ -1428,45 +1139,16 @@
      *         {@code null} if no threads are currently queued
      */
     public final Thread getFirstQueuedThread() {
-        // handle only fast path, else relay
-        return (head == tail) ? null : fullGetFirstQueuedThread();
-    }
-
-    /**
-     * Version of getFirstQueuedThread called when fastpath fails.
-     */
-    private Thread fullGetFirstQueuedThread() {
-        /*
-         * The first node is normally head.next. Try to get its
-         * thread field, ensuring consistent reads: If thread
-         * field is nulled out or s.prev is no longer head, then
-         * some other thread(s) concurrently performed setHead in
-         * between some of our reads. We try this twice before
-         * resorting to traversal.
-         */
-        Node h, s;
-        Thread st;
-        if (((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null) ||
-            ((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null))
-            return st;
-
-        /*
-         * Head's next field might not have been set yet, or may have
-         * been unset after setHead. So we must check to see if tail
-         * is actually first node. If not, we continue on, safely
-         * traversing from tail back to head to find first,
-         * guaranteeing termination.
-         */
-
-        Thread firstThread = null;
-        for (Node p = tail; p != null && p != head; p = p.prev) {
-            Thread t = p.thread;
-            if (t != null)
-                firstThread = t;
+        Thread first = null, w; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null)) {
+            // traverse from tail on stale reads
+            for (Node p = tail, q; p != null && (q = p.prev) != null; p = q)
+                if ((w = p.waiter) != null)
+                    first = w;
         }
-        return firstThread;
+        return first;
     }
 
     /**
@@ -1483,7 +1165,7 @@
         if (thread == null)
             throw new NullPointerException();
         for (Node p = tail; p != null; p = p.prev)
-            if (p.thread == thread)
+            if (p.waiter == thread)
                 return true;
         return false;
     }
@@ -1499,10 +1181,8 @@
      */
     final boolean apparentlyFirstQueuedIsExclusive() {
         Node h, s;
-        return (h = head) != null &&
-            (s = h.next)  != null &&
-            !s.isShared()         &&
-            s.thread != null;
+        return (h = head) != null && (s = h.next)  != null &&
+            !(s instanceof SharedNode) && s.waiter != null;
     }
 
     /**
@@ -1549,19 +1229,12 @@
      * @since 1.7
      */
     public final boolean hasQueuedPredecessors() {
-        Node h, s;
-        if ((h = head) != null) {
-            if ((s = h.next) == null || s.waitStatus > 0) {
-                s = null; // traverse in case of concurrent cancellation
-                for (Node p = tail; p != h && p != null; p = p.prev) {
-                    if (p.waitStatus <= 0)
-                        s = p;
-                }
-            }
-            if (s != null && s.thread != Thread.currentThread())
-                return true;
-        }
-        return false;
+        Thread first = null; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null))
+            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
+        return first != null && first != Thread.currentThread();
     }
 
     // Instrumentation and monitoring methods
@@ -1578,7 +1251,7 @@
     public final int getQueueLength() {
         int n = 0;
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.thread != null)
+            if (p.waiter != null)
                 ++n;
         }
         return n;
@@ -1598,7 +1271,7 @@
     public final Collection<Thread> getQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            Thread t = p.thread;
+            Thread t = p.waiter;
             if (t != null)
                 list.add(t);
         }
@@ -1616,8 +1289,8 @@
     public final Collection<Thread> getExclusiveQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (!p.isShared()) {
-                Thread t = p.thread;
+            if (!(p instanceof SharedNode)) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1636,8 +1309,8 @@
     public final Collection<Thread> getSharedQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.isShared()) {
-                Thread t = p.thread;
+            if (p instanceof SharedNode) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1660,117 +1333,6 @@
             + (hasQueuedThreads() ? "non" : "") + "empty queue]";
     }
 
-
-    // Internal support methods for Conditions
-
-    /**
-     * Returns true if a node, always one that was initially placed on
-     * a condition queue, is now waiting to reacquire on sync queue.
-     * @param node the node
-     * @return true if is reacquiring
-     */
-    final boolean isOnSyncQueue(Node node) {
-        if (node.waitStatus == Node.CONDITION || node.prev == null)
-            return false;
-        if (node.next != null) // If has successor, it must be on queue
-            return true;
-        /*
-         * node.prev can be non-null, but not yet on queue because
-         * the CAS to place it on queue can fail. So we have to
-         * traverse from tail to make sure it actually made it.  It
-         * will always be near the tail in calls to this method, and
-         * unless the CAS failed (which is unlikely), it will be
-         * there, so we hardly ever traverse much.
-         */
-        return findNodeFromTail(node);
-    }
-
-    /**
-     * Returns true if node is on sync queue by searching backwards from tail.
-     * Called only when needed by isOnSyncQueue.
-     * @return true if present
-     */
-    private boolean findNodeFromTail(Node node) {
-        // We check for node first, since it's likely to be at or near tail.
-        // tail is known to be non-null, so we could re-order to "save"
-        // one null check, but we leave it this way to help the VM.
-        for (Node p = tail;;) {
-            if (p == node)
-                return true;
-            if (p == null)
-                return false;
-            p = p.prev;
-        }
-    }
-
-    /**
-     * Transfers a node from a condition queue onto sync queue.
-     * Returns true if successful.
-     * @param node the node
-     * @return true if successfully transferred (else the node was
-     * cancelled before signal)
-     */
-    final boolean transferForSignal(Node node) {
-        /*
-         * If cannot change waitStatus, the node has been cancelled.
-         */
-        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
-            return false;
-
-        /*
-         * Splice onto queue and try to set waitStatus of predecessor to
-         * indicate that thread is (probably) waiting. If cancelled or
-         * attempt to set waitStatus fails, wake up to resync (in which
-         * case the waitStatus can be transiently and harmlessly wrong).
-         */
-        Node p = enq(node);
-        int ws = p.waitStatus;
-        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
-            LockSupport.unpark(node.thread);
-        return true;
-    }
-
-    /**
-     * Transfers node, if necessary, to sync queue after a cancelled wait.
-     * Returns true if thread was cancelled before being signalled.
-     *
-     * @param node the node
-     * @return true if cancelled before the node was signalled
-     */
-    final boolean transferAfterCancelledWait(Node node) {
-        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
-            enq(node);
-            return true;
-        }
-        /*
-         * If we lost out to a signal(), then we can't proceed
-         * until it finishes its enq().  Cancelling during an
-         * incomplete transfer is both rare and transient, so just
-         * spin.
-         */
-        while (!isOnSyncQueue(node))
-            Thread.yield();
-        return false;
-    }
-
-    /**
-     * Invokes release with current state value; returns saved state.
-     * Cancels node and throws exception on failure.
-     * @param node the condition node for this wait
-     * @return previous sync state
-     */
-    final int fullyRelease(Node node) {
-        try {
-            int savedState = getState();
-            if (release(savedState))
-                return savedState;
-            throw new IllegalMonitorStateException();
-        } catch (Throwable t) {
-            node.waitStatus = Node.CANCELLED;
-            throw t;
-        }
-    }
-
     // Instrumentation methods for conditions
 
     /**
@@ -1868,106 +1430,34 @@
     public class ConditionObject implements Condition, java.io.Serializable {
         private static final long serialVersionUID = 1173984872572414699L;
         /** First node of condition queue. */
-        private transient Node firstWaiter;
+        private transient ConditionNode firstWaiter;
         /** Last node of condition queue. */
-        private transient Node lastWaiter;
+        private transient ConditionNode lastWaiter;
 
         /**
          * Creates a new {@code ConditionObject} instance.
          */
         public ConditionObject() { }
 
-        // Internal methods
-
-        /**
-         * Adds a new waiter to wait queue.
-         * @return its new wait node
-         */
-        private Node addConditionWaiter() {
-            if (!isHeldExclusively())
-                throw new IllegalMonitorStateException();
-            Node t = lastWaiter;
-            // If lastWaiter is cancelled, clean out.
-            if (t != null && t.waitStatus != Node.CONDITION) {
-                unlinkCancelledWaiters();
-                t = lastWaiter;
-            }
-
-            Node node = new Node(Node.CONDITION);
-
-            if (t == null)
-                firstWaiter = node;
-            else
-                t.nextWaiter = node;
-            lastWaiter = node;
-            return node;
-        }
-
-        /**
-         * Removes and transfers nodes until hit non-cancelled one or
-         * null. Split out from signal in part to encourage compilers
-         * to inline the case of no waiters.
-         * @param first (non-null) the first node on condition queue
-         */
-        private void doSignal(Node first) {
-            do {
-                if ( (firstWaiter = first.nextWaiter) == null)
-                    lastWaiter = null;
-                first.nextWaiter = null;
-            } while (!transferForSignal(first) &&
-                     (first = firstWaiter) != null);
-        }
+        // Signalling methods
 
         /**
-         * Removes and transfers all nodes.
-         * @param first (non-null) the first node on condition queue
+         * Removes and transfers one or all waiters to sync queue.
          */
-        private void doSignalAll(Node first) {
-            lastWaiter = firstWaiter = null;
-            do {
-                Node next = first.nextWaiter;
-                first.nextWaiter = null;
-                transferForSignal(first);
+        private void doSignal(ConditionNode first, boolean all) {
+            while (first != null) {
+                ConditionNode next = first.nextWaiter;
+                if ((firstWaiter = next) == null)
+                    lastWaiter = null;
+                if ((first.getAndUnsetStatus(COND) & COND) != 0) {
+                    enqueue(first);
+                    if (!all)
+                        break;
+                }
                 first = next;
-            } while (first != null);
-        }
-
-        /**
-         * Unlinks cancelled waiter nodes from condition queue.
-         * Called only while holding lock. This is called when
-         * cancellation occurred during condition wait, and upon
-         * insertion of a new waiter when lastWaiter is seen to have
-         * been cancelled. This method is needed to avoid garbage
-         * retention in the absence of signals. So even though it may
-         * require a full traversal, it comes into play only when
-         * timeouts or cancellations occur in the absence of
-         * signals. It traverses all nodes rather than stopping at a
-         * particular target to unlink all pointers to garbage nodes
-         * without requiring many re-traversals during cancellation
-         * storms.
-         */
-        private void unlinkCancelledWaiters() {
-            Node t = firstWaiter;
-            Node trail = null;
-            while (t != null) {
-                Node next = t.nextWaiter;
-                if (t.waitStatus != Node.CONDITION) {
-                    t.nextWaiter = null;
-                    if (trail == null)
-                        firstWaiter = next;
-                    else
-                        trail.nextWaiter = next;
-                    if (next == null)
-                        lastWaiter = trail;
-                }
-                else
-                    trail = t;
-                t = next;
             }
         }
 
-        // public methods
-
         /**
          * Moves the longest-waiting thread, if one exists, from the
          * wait queue for this condition to the wait queue for the
@@ -1977,11 +1467,11 @@
          *         returns {@code false}
          */
         public final void signal() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignal(first);
+                doSignal(first, false);
         }
 
         /**
@@ -1992,11 +1482,72 @@
          *         returns {@code false}
          */
         public final void signalAll() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignalAll(first);
+                doSignal(first, true);
+        }
+
+        // Waiting methods
+
+        /**
+         * Adds node to condition list and releases lock.
+         *
+         * @param node the node
+         * @return savedState to reacquire after wait
+         */
+        private int enableWait(ConditionNode node) {
+            if (isHeldExclusively()) {
+                node.waiter = Thread.currentThread();
+                node.setStatusRelaxed(COND | WAITING);
+                ConditionNode last = lastWaiter;
+                if (last == null)
+                    firstWaiter = node;
+                else
+                    last.nextWaiter = node;
+                lastWaiter = node;
+                int savedState = getState();
+                if (release(savedState))
+                    return savedState;
+            }
+            node.status = CANCELLED; // lock not held or inconsistent
+            throw new IllegalMonitorStateException();
+        }
+
+        /**
+         * Returns true if a node that was initially placed on a condition
+         * queue is now ready to reacquire on sync queue.
+         * @param node the node
+         * @return true if is reacquiring
+         */
+        private boolean canReacquire(ConditionNode node) {
+            // check links, not status to avoid enqueue race
+            return node != null && node.prev != null && isEnqueued(node);
+        }
+
+        /**
+         * Unlinks the given node and other non-waiting nodes from
+         * condition queue unless already unlinked.
+         */
+        private void unlinkCancelledWaiters(ConditionNode node) {
+            if (node == null || node.nextWaiter != null || node == lastWaiter) {
+                ConditionNode w = firstWaiter, trail = null;
+                while (w != null) {
+                    ConditionNode next = w.nextWaiter;
+                    if ((w.status & COND) == 0) {
+                        w.nextWaiter = null;
+                        if (trail == null)
+                            firstWaiter = next;
+                        else
+                            trail.nextWaiter = next;
+                        if (next == null)
+                            lastWaiter = trail;
+                    } else
+                        trail = w;
+                    w = next;
+                }
+            }
         }
 
         /**
@@ -2011,51 +1562,27 @@
          * </ol>
          */
         public final void awaitUninterruptibly() {
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
             boolean interrupted = false;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
+            while (!canReacquire(node)) {
                 if (Thread.interrupted())
                     interrupted = true;
+                else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) || interrupted)
-                selfInterrupt();
-        }
-
-        /*
-         * For interruptible waits, we need to track whether to throw
-         * InterruptedException, if interrupted while blocked on
-         * condition, versus reinterrupt current thread, if
-         * interrupted while blocked waiting to re-acquire.
-         */
-
-        /** Mode meaning to reinterrupt on exit from wait */
-        private static final int REINTERRUPT =  1;
-        /** Mode meaning to throw InterruptedException on exit from wait */
-        private static final int THROW_IE    = -1;
-
-        /**
-         * Checks for interrupt, returning THROW_IE if interrupted
-         * before signalled, REINTERRUPT if after signalled, or
-         * 0 if not interrupted.
-         */
-        private int checkInterruptWhileWaiting(Node node) {
-            return Thread.interrupted() ?
-                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
-                0;
-        }
-
-        /**
-         * Throws InterruptedException, reinterrupts current thread, or
-         * does nothing, depending on mode.
-         */
-        private void reportInterruptAfterWait(int interruptMode)
-            throws InterruptedException {
-            if (interruptMode == THROW_IE)
-                throw new InterruptedException();
-            else if (interruptMode == REINTERRUPT)
-                selfInterrupt();
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted)
+                Thread.currentThread().interrupt();
         }
 
         /**
@@ -2074,20 +1601,33 @@
         public final void await() throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
+            boolean interrupted = false, cancelled = false;
+            while (!canReacquire(node)) {
+                if (interrupted |= Thread.interrupted()) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;              // else interrupted after signal
+                } else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null) // clean up if cancelled
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted) {
+                if (cancelled) {
+                    unlinkCancelledWaiters(node);
+                    throw new InterruptedException();
+                }
+                Thread.currentThread().interrupt();
+            }
         }
 
         /**
@@ -2107,32 +1647,29 @@
                 throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // awaitNanos(0) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            long initialNanos = nanosTimeout;
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
             long remaining = deadline - System.nanoTime(); // avoid overflow
-            return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+            return (remaining <= nanosTimeout) ? remaining : Long.MIN_VALUE;
         }
 
         /**
@@ -2154,26 +1691,26 @@
             long abstime = deadline.getTime();
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (System.currentTimeMillis() >= abstime) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                LockSupport.parkUntil(this, abstime);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    System.currentTimeMillis() >= abstime) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkUntil(this, abstime);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         /**
@@ -2195,31 +1732,28 @@
             long nanosTimeout = unit.toNanos(time);
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // await(0, unit) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         //  support for instrumentation
@@ -2245,8 +1779,8 @@
         protected final boolean hasWaiters() {
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     return true;
             }
             return false;
@@ -2265,8 +1799,8 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             int n = 0;
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     ++n;
             }
             return n;
@@ -2285,9 +1819,9 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             ArrayList<Thread> list = new ArrayList<>();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION) {
-                    Thread t = w.thread;
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0) {
+                    Thread t = w.waiter;
                     if (t != null)
                         list.add(t);
                 }
@@ -2296,39 +1830,16 @@
         }
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATE;
-    private static final VarHandle HEAD;
-    private static final VarHandle TAIL;
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "tail");
 
     static {
-        try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(AbstractQueuedSynchronizer.class, "state", int.class);
-            HEAD = l.findVarHandle(AbstractQueuedSynchronizer.class, "head", Node.class);
-            TAIL = l.findVarHandle(AbstractQueuedSynchronizer.class, "tail", Node.class);
-        } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
-        }
-
-        // Reduce the risk of rare disastrous classloading in first call to
-        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
         Class<?> ensureLoaded = LockSupport.class;
     }
-
-    /**
-     * Initializes head and tail fields on first contention.
-     */
-    private final void initializeSyncQueue() {
-        Node h;
-        if (HEAD.compareAndSet(this, null, (h = new Node())))
-            tail = h;
-    }
-
-    /**
-     * CASes tail field.
-     */
-    private final boolean compareAndSetTail(Node expect, Node update) {
-        return TAIL.compareAndSet(this, expect, update);
-    }
 }
--- a/src/java.base/share/classes/java/util/concurrent/locks/Lock.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/Lock.java	Sun Sep 15 13:41:19 2019 +0200
@@ -122,9 +122,8 @@
  * <p>All {@code Lock} implementations <em>must</em> enforce the same
  * memory synchronization semantics as provided by the built-in monitor
  * lock, as described in
- * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4">
  * Chapter 17 of
- * <cite>The Java&trade; Language Specification</cite></a>:
+ * <cite>The Java&trade; Language Specification</cite>:
  * <ul>
  * <li>A successful {@code lock} operation has the same memory
  * synchronization effects as a successful <em>Lock</em> action.
@@ -162,6 +161,7 @@
  * @see ReentrantLock
  * @see Condition
  * @see ReadWriteLock
+ * @jls 17.4 Memory Model
  *
  * @since 1.5
  * @author Doug Lea
--- a/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Sun Sep 15 13:41:19 2019 +0200
@@ -140,8 +140,25 @@
     private LockSupport() {} // Cannot be instantiated.
 
     private static void setBlocker(Thread t, Object arg) {
-        // Even though volatile, hotspot doesn't need a write barrier here.
-        U.putReference(t, PARKBLOCKER, arg);
+        U.putReferenceOpaque(t, PARKBLOCKER, arg);
+    }
+
+    /**
+     * Sets the object to be returned by invocations of {@link
+     * #getBlocker getBlocker} for the current thread. This method may
+     * be used before invoking the no-argument version of {@link
+     * LockSupport#park() park()} from non-public objects, allowing
+     * more helpful diagnostics, or retaining compatibility with
+     * previous implementations of blocking methods.  Previous values
+     * of the blocker are not automatically restored after blocking.
+     * To obtain the effects of {@code park(b}}, use {@code
+     * setCurrentBlocker(b); park(); setCurrentBlocker(null);}
+     *
+     * @param blocker the blocker object
+     * @since 14
+     */
+    public static void setCurrentBlocker(Object blocker) {
+        U.putReferenceOpaque(Thread.currentThread(), PARKBLOCKER, blocker);
     }
 
     /**
@@ -292,7 +309,7 @@
     public static Object getBlocker(Thread t) {
         if (t == null)
             throw new NullPointerException();
-        return U.getReferenceVolatile(t, PARKBLOCKER);
+        return U.getReferenceOpaque(t, PARKBLOCKER);
     }
 
     /**
@@ -394,24 +411,6 @@
     }
 
     /**
-     * Returns the pseudo-randomly initialized or updated secondary seed.
-     * Copied from ThreadLocalRandom due to package access restrictions.
-     */
-    static final int nextSecondarySeed() {
-        int r;
-        Thread t = Thread.currentThread();
-        if ((r = U.getInt(t, SECONDARY)) != 0) {
-            r ^= r << 13;   // xorshift
-            r ^= r >>> 17;
-            r ^= r << 5;
-        }
-        else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
-            r = 1; // avoid zero
-        U.putInt(t, SECONDARY, r);
-        return r;
-    }
-
-    /**
      * Returns the thread id for the given thread.  We must access
      * this directly rather than via method Thread.getId() because
      * getId() has been known to be overridden in ways that do not
@@ -423,11 +422,9 @@
 
     // Hotspot implementation via intrinsics API
     private static final Unsafe U = Unsafe.getUnsafe();
-    private static final long PARKBLOCKER = U.objectFieldOffset
-            (Thread.class, "parkBlocker");
-    private static final long SECONDARY = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomSecondarySeed");
-    private static final long TID = U.objectFieldOffset
-            (Thread.class, "tid");
+    private static final long PARKBLOCKER
+        = U.objectFieldOffset(Thread.class, "parkBlocker");
+    private static final long TID
+        = U.objectFieldOffset(Thread.class, "tid");
 
 }
--- a/src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java	Sun Sep 15 13:41:19 2019 +0200
@@ -119,39 +119,63 @@
         private static final long serialVersionUID = -5179523762034025860L;
 
         /**
-         * Performs non-fair tryLock.  tryAcquire is implemented in
-         * subclasses, but both need nonfair try for trylock method.
+         * Performs non-fair tryLock.
          */
         @ReservedStackAccess
-        final boolean nonfairTryAcquire(int acquires) {
-            final Thread current = Thread.currentThread();
+        final boolean tryLock() {
+            Thread current = Thread.currentThread();
             int c = getState();
             if (c == 0) {
-                if (compareAndSetState(0, acquires)) {
+                if (compareAndSetState(0, 1)) {
                     setExclusiveOwnerThread(current);
                     return true;
                 }
-            }
-            else if (current == getExclusiveOwnerThread()) {
-                int nextc = c + acquires;
-                if (nextc < 0) // overflow
+            } else if (getExclusiveOwnerThread() == current) {
+                if (++c < 0) // overflow
                     throw new Error("Maximum lock count exceeded");
-                setState(nextc);
+                setState(c);
                 return true;
             }
             return false;
         }
 
+        /**
+         * Checks for reentrancy and acquires if lock immediately
+         * available under fair vs nonfair rules. Locking methods
+         * perform initialTryLock check before relaying to
+         * corresponding AQS acquire methods.
+         */
+        abstract boolean initialTryLock();
+
+        @ReservedStackAccess
+        final void lock() {
+            if (!initialTryLock())
+                acquire(1);
+        }
+
+        @ReservedStackAccess
+        final void lockInterruptibly() throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            if (!initialTryLock())
+                acquireInterruptibly(1);
+        }
+
+        @ReservedStackAccess
+        final boolean tryLockNanos(long nanos) throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            return initialTryLock() || tryAcquireNanos(1, nanos);
+        }
+
         @ReservedStackAccess
         protected final boolean tryRelease(int releases) {
             int c = getState() - releases;
-            if (Thread.currentThread() != getExclusiveOwnerThread())
+            if (getExclusiveOwnerThread() != Thread.currentThread())
                 throw new IllegalMonitorStateException();
-            boolean free = false;
-            if (c == 0) {
-                free = true;
+            boolean free = (c == 0);
+            if (free)
                 setExclusiveOwnerThread(null);
-            }
             setState(c);
             return free;
         }
@@ -195,8 +219,31 @@
      */
     static final class NonfairSync extends Sync {
         private static final long serialVersionUID = 7316153563782823691L;
+
+        final boolean initialTryLock() {
+            Thread current = Thread.currentThread();
+            if (compareAndSetState(0, 1)) { // first attempt is unguarded
+                setExclusiveOwnerThread(current);
+                return true;
+            } else if (getExclusiveOwnerThread() == current) {
+                int c = getState() + 1;
+                if (c < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(c);
+                return true;
+            } else
+                return false;
+        }
+
+        /**
+         * Acquire for non-reentrant cases after initialTryLock prescreen
+         */
         protected final boolean tryAcquire(int acquires) {
-            return nonfairTryAcquire(acquires);
+            if (getState() == 0 && compareAndSetState(0, acquires)) {
+                setExclusiveOwnerThread(Thread.currentThread());
+                return true;
+            }
+            return false;
         }
     }
 
@@ -205,26 +252,34 @@
      */
     static final class FairSync extends Sync {
         private static final long serialVersionUID = -3000897897090466540L;
+
         /**
-         * Fair version of tryAcquire.  Don't grant access unless
-         * recursive call or no waiters or is first.
+         * Acquires only if reentrant or queue is empty.
          */
-        @ReservedStackAccess
-        protected final boolean tryAcquire(int acquires) {
-            final Thread current = Thread.currentThread();
+        final boolean initialTryLock() {
+            Thread current = Thread.currentThread();
             int c = getState();
             if (c == 0) {
-                if (!hasQueuedPredecessors() &&
-                    compareAndSetState(0, acquires)) {
+                if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
                     setExclusiveOwnerThread(current);
                     return true;
                 }
+            } else if (getExclusiveOwnerThread() == current) {
+                if (++c < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(c);
+                return true;
             }
-            else if (current == getExclusiveOwnerThread()) {
-                int nextc = c + acquires;
-                if (nextc < 0)
-                    throw new Error("Maximum lock count exceeded");
-                setState(nextc);
+            return false;
+        }
+
+        /**
+         * Acquires only if thread is first waiter or empty
+         */
+        protected final boolean tryAcquire(int acquires) {
+            if (getState() == 0 && !hasQueuedPredecessors() &&
+                compareAndSetState(0, acquires)) {
+                setExclusiveOwnerThread(Thread.currentThread());
                 return true;
             }
             return false;
@@ -264,7 +319,7 @@
      * at which time the lock hold count is set to one.
      */
     public void lock() {
-        sync.acquire(1);
+        sync.lock();
     }
 
     /**
@@ -314,7 +369,7 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public void lockInterruptibly() throws InterruptedException {
-        sync.acquireInterruptibly(1);
+        sync.lockInterruptibly();
     }
 
     /**
@@ -344,7 +399,7 @@
      *         thread; and {@code false} otherwise
      */
     public boolean tryLock() {
-        return sync.nonfairTryAcquire(1);
+        return sync.tryLock();
     }
 
     /**
@@ -421,7 +476,7 @@
      */
     public boolean tryLock(long timeout, TimeUnit unit)
             throws InterruptedException {
-        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+        return sync.tryLockNanos(unit.toNanos(timeout));
     }
 
     /**
--- a/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Sun Sep 15 13:41:19 2019 +0200
@@ -35,9 +35,8 @@
 
 package java.util.concurrent.locks;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.concurrent.TimeUnit;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.vm.annotation.ReservedStackAccess;
 
 /**
@@ -132,9 +131,8 @@
  *
  * <p><b>Memory Synchronization.</b> Methods with the effect of
  * successfully locking in any mode have the same memory
- * synchronization effects as a <em>Lock</em> action described in
- * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4">
- * Chapter 17 of <cite>The Java&trade; Language Specification</cite></a>.
+ * synchronization effects as a <em>Lock</em> action, as described in
+ * Chapter 17 of <cite>The Java&trade; Language Specification</cite>.
  * Methods successfully unlocking in write mode have the same memory
  * synchronization effects as an <em>Unlock</em> action.  In optimistic
  * read usages, actions prior to the most recent write mode unlock action
@@ -237,6 +235,7 @@
  *   }
  * }}</pre>
  *
+ * @jls 17.4 Memory Model
  * @since 1.8
  * @author Doug Lea
  */
@@ -264,122 +263,54 @@
      * updates.
      *
      * Waiters use a modified form of CLH lock used in
-     * AbstractQueuedSynchronizer (see its internal documentation for
-     * a fuller account), where each node is tagged (field mode) as
-     * either a reader or writer. Sets of waiting readers are grouped
-     * (linked) under a common node (field cowait) so act as a single
-     * node with respect to most CLH mechanics.  By virtue of the
-     * queue structure, wait nodes need not actually carry sequence
-     * numbers; we know each is greater than its predecessor.  This
-     * simplifies the scheduling policy to a mainly-FIFO scheme that
-     * incorporates elements of Phase-Fair locks (see Brandenburg &
-     * Anderson, especially http://www.cs.unc.edu/~bbb/diss/).  In
-     * particular, we use the phase-fair anti-barging rule: If an
-     * incoming reader arrives while read lock is held but there is a
-     * queued writer, this incoming reader is queued.  (This rule is
-     * responsible for some of the complexity of method acquireRead,
-     * but without it, the lock becomes highly unfair.) Method release
-     * does not (and sometimes cannot) itself wake up cowaiters. This
-     * is done by the primary thread, but helped by any other threads
-     * with nothing better to do in methods acquireRead and
-     * acquireWrite.
+     * AbstractQueuedSynchronizer (AQS; see its internal documentation
+     * for a fuller account), where each node is either a ReaderNode
+     * or WriterNode. Implementation of queued Writer mode is
+     * identical to AQS except for lock-state operations.  Sets of
+     * waiting readers are grouped (linked) under a common node (field
+     * cowaiters) so act as a single node with respect to most CLH
+     * mechanics.  This simplifies the scheduling policy to a
+     * mainly-FIFO scheme that incorporates elements of Phase-Fair
+     * locks (see Brandenburg & Anderson, especially
+     * http://www.cs.unc.edu/~bbb/diss/).  Method release does not
+     * itself wake up cowaiters. This is done by the primary thread,
+     * but helped by other cowaiters as they awaken.
      *
-     * These rules apply to threads actually queued. All tryLock forms
-     * opportunistically try to acquire locks regardless of preference
-     * rules, and so may "barge" their way in.  Randomized spinning is
-     * used in the acquire methods to reduce (increasingly expensive)
-     * context switching while also avoiding sustained memory
-     * thrashing among many threads.  We limit spins to the head of
-     * queue. If, upon wakening, a thread fails to obtain lock, and is
-     * still (or becomes) the first waiting thread (which indicates
-     * that some other thread barged and obtained lock), it escalates
-     * spins (up to MAX_HEAD_SPINS) to reduce the likelihood of
-     * continually losing to barging threads.
+     * These rules apply to threads actually queued. Threads may also
+     * try to acquire locks before or in the process of enqueueing
+     * regardless of preference rules, and so may "barge" their way
+     * in.  Methods writeLock and readLock (but not the other variants
+     * of each) first unconditionally try to CAS state, falling back
+     * to test-and-test-and-set retries on failure, slightly shrinking
+     * race windows on initial attempts, thus making success more
+     * likely. Also, when some threads cancel (via interrupt or
+     * timeout), phase-fairness is at best roughly approximated.
      *
      * Nearly all of these mechanics are carried out in methods
      * acquireWrite and acquireRead, that, as typical of such code,
      * sprawl out because actions and retries rely on consistent sets
      * of locally cached reads.
      *
-     * As noted in Boehm's paper (above), sequence validation (mainly
-     * method validate()) requires stricter ordering rules than apply
-     * to normal volatile reads (of "state").  To force orderings of
-     * reads before a validation and the validation itself in those
-     * cases where this is not already forced, we use acquireFence.
-     * Unlike in that paper, we allow writers to use plain writes.
-     * One would not expect reorderings of such writes with the lock
-     * acquisition CAS because there is a "control dependency", but it
-     * is theoretically possible, so we additionally add a
-     * storeStoreFence after lock acquisition CAS.
-     *
-     * ----------------------------------------------------------------
-     * Here's an informal proof that plain reads by _successful_
-     * readers see plain writes from preceding but not following
-     * writers (following Boehm and the C++ standard [atomics.fences]):
-     *
-     * Because of the total synchronization order of accesses to
-     * volatile long state containing the sequence number, writers and
-     * _successful_ readers can be globally sequenced.
-     *
-     * int x, y;
-     *
-     * Writer 1:
-     * inc sequence (odd - "locked")
-     * storeStoreFence();
-     * x = 1; y = 2;
-     * inc sequence (even - "unlocked")
-     *
-     * Successful Reader:
-     * read sequence (even)
-     * // must see writes from Writer 1 but not Writer 2
-     * r1 = x; r2 = y;
-     * acquireFence();
-     * read sequence (even - validated unchanged)
-     * // use r1 and r2
-     *
-     * Writer 2:
-     * inc sequence (odd - "locked")
-     * storeStoreFence();
-     * x = 3; y = 4;
-     * inc sequence (even - "unlocked")
-     *
-     * Visibility of writer 1's stores is normal - reader's initial
-     * read of state synchronizes with writer 1's final write to state.
-     * Lack of visibility of writer 2's plain writes is less obvious.
-     * If reader's read of x or y saw writer 2's write, then (assuming
-     * semantics of C++ fences) the storeStoreFence would "synchronize"
-     * with reader's acquireFence and reader's validation read must see
-     * writer 2's initial write to state and so validation must fail.
-     * But making this "proof" formal and rigorous is an open problem!
-     * ----------------------------------------------------------------
+     * For an explanation of the use of acquireFence, see
+     * http://gee.cs.oswego.edu/dl/html/j9mm.html as well as Boehm's
+     * paper (above). Note that sequence validation (mainly method
+     * validate()) requires stricter ordering rules than apply to
+     * normal volatile reads (of "state").  To ensure that writeLock
+     * acquisitions strictly precede subsequent writes in cases where
+     * this is not already forced, we use a storeStoreFence.
      *
      * The memory layout keeps lock state and queue pointers together
      * (normally on the same cache line). This usually works well for
      * read-mostly loads. In most other cases, the natural tendency of
-     * adaptive-spin CLH locks to reduce memory contention lessens
-     * motivation to further spread out contended locations, but might
-     * be subject to future improvements.
+     * CLH locks to reduce memory contention lessens motivation to
+     * further spread out contended locations, but might be subject to
+     * future improvements.
      */
 
     private static final long serialVersionUID = -6001602636862214147L;
 
-    /** Number of processors, for spin control */
-    private static final int NCPU = Runtime.getRuntime().availableProcessors();
-
-    /** Maximum number of retries before enqueuing on acquisition; at least 1 */
-    private static final int SPINS = (NCPU > 1) ? 1 << 6 : 1;
-
-    /** Maximum number of tries before blocking at head on acquisition */
-    private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 1;
-
-    /** Maximum number of retries before re-blocking */
-    private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 1;
-
-    /** The period for yielding when waiting for overflow spinlock */
-    private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
-
     /** The number of bits to use for reader count before overflowing */
-    private static final int LG_READERS = 7;
+    private static final int LG_READERS = 7; // 127 readers
 
     // Values for lock state and stamp operations
     private static final long RUNIT = 1L;
@@ -388,6 +319,8 @@
     private static final long RFULL = RBITS - 1L;
     private static final long ABITS = RBITS | WBIT;
     private static final long SBITS = ~RBITS; // note overlap with ABITS
+    // not writing and conservatively non-overflowing
+    private static final long RSAFE = ~(3L << (LG_READERS - 1));
 
     /*
      * 3 stamp modes can be distinguished by examining (m = stamp & ABITS):
@@ -408,29 +341,64 @@
     // Special value from cancelled acquire methods so caller can throw IE
     private static final long INTERRUPTED = 1L;
 
-    // Values for node status; order matters
-    private static final int WAITING   = -1;
-    private static final int CANCELLED =  1;
+    // Bits for Node.status
+    static final int WAITING   = 1;
+    static final int CANCELLED = 0x80000000; // must be negative
 
-    // Modes for nodes (int not boolean to allow arithmetic)
-    private static final int RMODE = 0;
-    private static final int WMODE = 1;
+    /** CLH nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
 
-    /** Wait nodes */
-    static final class WNode {
-        volatile WNode prev;
-        volatile WNode next;
-        volatile WNode cowait;    // list of linked readers
-        volatile Thread thread;   // non-null while possibly parked
-        volatile int status;      // 0, WAITING, or CANCELLED
-        final int mode;           // RMODE or WMODE
-        WNode(int m, WNode p) { mode = m; prev = p; }
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
+
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
+
+    static final class WriterNode extends Node { // node for writers
+    }
+
+    static final class ReaderNode extends Node { // node for readers
+        volatile ReaderNode cowaiters;           // list of linked readers
+        final boolean casCowaiters(ReaderNode c, ReaderNode v) {
+            return U.weakCompareAndSetReference(this, COWAITERS, c, v);
+        }
+        final void setCowaitersRelaxed(ReaderNode p) {
+            U.putReference(this, COWAITERS, p);
+        }
+        private static final long COWAITERS
+            = U.objectFieldOffset(ReaderNode.class, "cowaiters");
     }
 
     /** Head of CLH queue */
-    private transient volatile WNode whead;
+    private transient volatile Node head;
     /** Tail (last) of CLH queue */
-    private transient volatile WNode wtail;
+    private transient volatile Node tail;
 
     // views
     transient ReadLockView readLockView;
@@ -449,18 +417,50 @@
         state = ORIGIN;
     }
 
-    private boolean casState(long expectedValue, long newValue) {
-        return STATE.compareAndSet(this, expectedValue, newValue);
+    // internal lock methods
+
+    private boolean casState(long expect, long update) {
+        return U.compareAndSetLong(this, STATE, expect, update);
+    }
+
+    @ReservedStackAccess
+    private long tryAcquireWrite() {
+        long s, nextState;
+        if (((s = state) & ABITS) == 0L && casState(s, nextState = s | WBIT)) {
+            U.storeStoreFence();
+            return nextState;
+        }
+        return 0L;
     }
 
-    private long tryWriteLock(long s) {
-        // assert (s & ABITS) == 0L;
-        long next;
-        if (casState(s, next = s | WBIT)) {
-            VarHandle.storeStoreFence();
-            return next;
+    @ReservedStackAccess
+    private long tryAcquireRead() {
+        for (long s, m, nextState;;) {
+            if ((m = (s = state) & ABITS) < RFULL) {
+                if (casState(s, nextState = s + RUNIT))
+                    return nextState;
+            }
+            else if (m == WBIT)
+                return 0L;
+            else if ((nextState = tryIncReaderOverflow(s)) != 0L)
+                return nextState;
         }
-        return 0L;
+    }
+
+    /**
+     * Returns an unlocked state, incrementing the version and
+     * avoiding special failure value 0L.
+     *
+     * @param s a write-locked state (or stamp)
+     */
+    private static long unlockWriteState(long s) {
+        return ((s += WBIT) == 0L) ? ORIGIN : s;
+    }
+
+    private long releaseWrite(long s) {
+        long nextState = state = unlockWriteState(s);
+        signalNext(head);
+        return nextState;
     }
 
     /**
@@ -471,8 +471,13 @@
      */
     @ReservedStackAccess
     public long writeLock() {
-        long next;
-        return ((next = tryWriteLock()) != 0L) ? next : acquireWrite(false, 0L);
+        // try unconditional CAS confirming weak read
+        long s = U.getLongOpaque(this, STATE) & ~ABITS, nextState;
+        if (casState(s, nextState = s | WBIT)) {
+            U.storeStoreFence();
+            return nextState;
+        }
+        return acquireWrite(false, false, 0L);
     }
 
     /**
@@ -481,10 +486,8 @@
      * @return a write stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      */
-    @ReservedStackAccess
     public long tryWriteLock() {
-        long s;
-        return (((s = state) & ABITS) == 0L) ? tryWriteLock(s) : 0L;
+        return tryAcquireWrite();
     }
 
     /**
@@ -504,15 +507,14 @@
         throws InterruptedException {
         long nanos = unit.toNanos(time);
         if (!Thread.interrupted()) {
-            long next, deadline;
-            if ((next = tryWriteLock()) != 0L)
-                return next;
+            long nextState;
+            if ((nextState = tryAcquireWrite()) != 0L)
+                return nextState;
             if (nanos <= 0L)
                 return 0L;
-            if ((deadline = System.nanoTime() + nanos) == 0L)
-                deadline = 1L;
-            if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
-                return next;
+            nextState = acquireWrite(true, true, System.nanoTime() + nanos);
+            if (nextState != INTERRUPTED)
+                return nextState;
         }
         throw new InterruptedException();
     }
@@ -527,12 +529,12 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    @ReservedStackAccess
     public long writeLockInterruptibly() throws InterruptedException {
-        long next;
+        long nextState;
         if (!Thread.interrupted() &&
-            (next = acquireWrite(true, 0L)) != INTERRUPTED)
-            return next;
+            ((nextState = tryAcquireWrite()) != 0L ||
+             (nextState = acquireWrite(true, false, 0L)) != INTERRUPTED))
+            return nextState;
         throw new InterruptedException();
     }
 
@@ -544,13 +546,12 @@
      */
     @ReservedStackAccess
     public long readLock() {
-        long s, next;
-        // bypass acquireRead on common uncontended case
-        return (whead == wtail
-                && ((s = state) & ABITS) < RFULL
-                && casState(s, next = s + RUNIT))
-            ? next
-            : acquireRead(false, 0L);
+        // unconditionally optimistically try non-overflow case once
+        long s = U.getLongOpaque(this, STATE) & RSAFE, nextState;
+        if (casState(s, nextState = s + RUNIT))
+            return nextState;
+        else
+            return acquireRead(false, false, 0L);
     }
 
     /**
@@ -559,18 +560,8 @@
      * @return a read stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      */
-    @ReservedStackAccess
     public long tryReadLock() {
-        long s, m, next;
-        while ((m = (s = state) & ABITS) != WBIT) {
-            if (m < RFULL) {
-                if (casState(s, next = s + RUNIT))
-                    return next;
-            }
-            else if ((next = tryIncReaderOverflow(s)) != 0L)
-                return next;
-        }
-        return 0L;
+        return tryAcquireRead();
     }
 
     /**
@@ -586,26 +577,18 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    @ReservedStackAccess
     public long tryReadLock(long time, TimeUnit unit)
         throws InterruptedException {
-        long s, m, next, deadline;
         long nanos = unit.toNanos(time);
         if (!Thread.interrupted()) {
-            if ((m = (s = state) & ABITS) != WBIT) {
-                if (m < RFULL) {
-                    if (casState(s, next = s + RUNIT))
-                        return next;
-                }
-                else if ((next = tryIncReaderOverflow(s)) != 0L)
-                    return next;
-            }
+            long nextState;
+            if (tail == head && (nextState = tryAcquireRead()) != 0L)
+                return nextState;
             if (nanos <= 0L)
                 return 0L;
-            if ((deadline = System.nanoTime() + nanos) == 0L)
-                deadline = 1L;
-            if ((next = acquireRead(true, deadline)) != INTERRUPTED)
-                return next;
+            nextState = acquireRead(true, true, System.nanoTime() + nanos);
+            if (nextState != INTERRUPTED)
+                return nextState;
         }
         throw new InterruptedException();
     }
@@ -620,17 +603,12 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    @ReservedStackAccess
     public long readLockInterruptibly() throws InterruptedException {
-        long s, next;
-        if (!Thread.interrupted()
-            // bypass acquireRead on common uncontended case
-            && ((whead == wtail
-                 && ((s = state) & ABITS) < RFULL
-                 && casState(s, next = s + RUNIT))
-                ||
-                (next = acquireRead(true, 0L)) != INTERRUPTED))
-            return next;
+        long nextState;
+        if (!Thread.interrupted() &&
+            ((nextState = tryAcquireRead()) != 0L ||
+             (nextState = acquireRead(true, false, 0L)) != INTERRUPTED))
+            return nextState;
         throw new InterruptedException();
     }
 
@@ -658,29 +636,11 @@
      * since issuance of the given stamp; else false
      */
     public boolean validate(long stamp) {
-        VarHandle.acquireFence();
+        U.loadFence();
         return (stamp & SBITS) == (state & SBITS);
     }
 
     /**
-     * Returns an unlocked state, incrementing the version and
-     * avoiding special failure value 0L.
-     *
-     * @param s a write-locked state (or stamp)
-     */
-    private static long unlockWriteState(long s) {
-        return ((s += WBIT) == 0L) ? ORIGIN : s;
-    }
-
-    private long unlockWriteInternal(long s) {
-        long next; WNode h;
-        STATE.setVolatile(this, next = unlockWriteState(s));
-        if ((h = whead) != null && h.status != 0)
-            release(h);
-        return next;
-    }
-
-    /**
      * If the lock state matches the given stamp, releases the
      * exclusive lock.
      *
@@ -692,7 +652,7 @@
     public void unlockWrite(long stamp) {
         if (state != stamp || (stamp & WBIT) == 0L)
             throw new IllegalMonitorStateException();
-        unlockWriteInternal(stamp);
+        releaseWrite(stamp);
     }
 
     /**
@@ -705,19 +665,20 @@
      */
     @ReservedStackAccess
     public void unlockRead(long stamp) {
-        long s, m; WNode h;
-        while (((s = state) & SBITS) == (stamp & SBITS)
-               && (stamp & RBITS) > 0L
-               && ((m = s & RBITS) > 0L)) {
-            if (m < RFULL) {
-                if (casState(s, s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
+        long s, m;
+        if ((stamp & RBITS) != 0L) {
+            while (((s = state) & SBITS) == (stamp & SBITS) &&
+                   ((m = s & RBITS) != 0L)) {
+                if (m < RFULL) {
+                    if (casState(s, s - RUNIT)) {
+                        if (m == RUNIT)
+                            signalNext(head);
+                        return;
+                    }
+                }
+                else if (tryDecReaderOverflow(s) != 0L)
                     return;
-                }
             }
-            else if (tryDecReaderOverflow(s) != 0L)
-                return;
         }
         throw new IllegalMonitorStateException();
     }
@@ -730,7 +691,6 @@
      * @throws IllegalMonitorStateException if the stamp does
      * not match the current state of this lock
      */
-    @ReservedStackAccess
     public void unlock(long stamp) {
         if ((stamp & WBIT) != 0L)
             unlockWrite(stamp);
@@ -751,26 +711,23 @@
      * @return a valid write stamp, or zero on failure
      */
     public long tryConvertToWriteLock(long stamp) {
-        long a = stamp & ABITS, m, s, next;
+        long a = stamp & ABITS, m, s, nextState;
         while (((s = state) & SBITS) == (stamp & SBITS)) {
             if ((m = s & ABITS) == 0L) {
                 if (a != 0L)
                     break;
-                if ((next = tryWriteLock(s)) != 0L)
-                    return next;
-            }
-            else if (m == WBIT) {
+                if (casState(s, nextState = s | WBIT)) {
+                    U.storeStoreFence();
+                    return nextState;
+                }
+            } else if (m == WBIT) {
                 if (a != m)
                     break;
                 return stamp;
-            }
-            else if (m == RUNIT && a != 0L) {
-                if (casState(s, next = s - RUNIT + WBIT)) {
-                    VarHandle.storeStoreFence();
-                    return next;
-                }
-            }
-            else
+            } else if (m == RUNIT && a != 0L) {
+                if (casState(s, nextState = s - RUNIT + WBIT))
+                    return nextState;
+            } else
                 break;
         }
         return 0L;
@@ -788,28 +745,21 @@
      * @return a valid read stamp, or zero on failure
      */
     public long tryConvertToReadLock(long stamp) {
-        long a, s, next; WNode h;
+        long a, s, nextState;
         while (((s = state) & SBITS) == (stamp & SBITS)) {
             if ((a = stamp & ABITS) >= WBIT) {
-                // write stamp
-                if (s != stamp)
+                if (s != stamp) // write stamp
                     break;
-                STATE.setVolatile(this, next = unlockWriteState(s) + RUNIT);
-                if ((h = whead) != null && h.status != 0)
-                    release(h);
-                return next;
-            }
-            else if (a == 0L) {
-                // optimistic read stamp
+                nextState = state = unlockWriteState(s) + RUNIT;
+                signalNext(head);
+                return nextState;
+            } else if (a == 0L) { // optimistic read stamp
                 if ((s & ABITS) < RFULL) {
-                    if (casState(s, next = s + RUNIT))
-                        return next;
-                }
-                else if ((next = tryIncReaderOverflow(s)) != 0L)
-                    return next;
-            }
-            else {
-                // already a read stamp
+                    if (casState(s, nextState = s + RUNIT))
+                        return nextState;
+                } else if ((nextState = tryIncReaderOverflow(s)) != 0L)
+                    return nextState;
+            } else { // already a read stamp
                 if ((s & ABITS) == 0L)
                     break;
                 return stamp;
@@ -829,29 +779,25 @@
      * @return a valid optimistic read stamp, or zero on failure
      */
     public long tryConvertToOptimisticRead(long stamp) {
-        long a, m, s, next; WNode h;
-        VarHandle.acquireFence();
+        long a, m, s, nextState;
+        U.loadFence();
         while (((s = state) & SBITS) == (stamp & SBITS)) {
             if ((a = stamp & ABITS) >= WBIT) {
-                // write stamp
-                if (s != stamp)
+                if (s != stamp)   // write stamp
                     break;
-                return unlockWriteInternal(s);
-            }
-            else if (a == 0L)
-                // already an optimistic read stamp
+                return releaseWrite(s);
+            } else if (a == 0L) { // already an optimistic read stamp
                 return stamp;
-            else if ((m = s & ABITS) == 0L) // invalid read stamp
+            } else if ((m = s & ABITS) == 0L) { // invalid read stamp
                 break;
-            else if (m < RFULL) {
-                if (casState(s, next = s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
-                    return next & SBITS;
+            } else if (m < RFULL) {
+                if (casState(s, nextState = s - RUNIT)) {
+                    if (m == RUNIT)
+                        signalNext(head);
+                    return nextState & SBITS;
                 }
-            }
-            else if ((next = tryDecReaderOverflow(s)) != 0L)
-                return next & SBITS;
+            } else if ((nextState = tryDecReaderOverflow(s)) != 0L)
+                return nextState & SBITS;
         }
         return 0L;
     }
@@ -867,7 +813,7 @@
     public boolean tryUnlockWrite() {
         long s;
         if (((s = state) & WBIT) != 0L) {
-            unlockWriteInternal(s);
+            releaseWrite(s);
             return true;
         }
         return false;
@@ -882,12 +828,12 @@
      */
     @ReservedStackAccess
     public boolean tryUnlockRead() {
-        long s, m; WNode h;
+        long s, m;
         while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
             if (m < RFULL) {
                 if (casState(s, s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
+                    if (m == RUNIT)
+                        signalNext(head);
                     return true;
                 }
             }
@@ -1133,16 +1079,16 @@
         long s;
         if (((s = state) & WBIT) == 0L)
             throw new IllegalMonitorStateException();
-        unlockWriteInternal(s);
+        releaseWrite(s);
     }
 
     final void unstampedUnlockRead() {
-        long s, m; WNode h;
+        long s, m;
         while ((m = (s = state) & RBITS) > 0L) {
             if (m < RFULL) {
                 if (casState(s, s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
+                    if (m == RUNIT)
+                        signalNext(head);
                     return;
                 }
             }
@@ -1155,10 +1101,10 @@
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
         s.defaultReadObject();
-        STATE.setVolatile(this, ORIGIN); // reset to unlocked state
+        state = ORIGIN; // reset to unlocked state
     }
 
-    // internals
+    // overflow handling methods
 
     /**
      * Tries to increment readerOverflow by first setting state
@@ -1170,17 +1116,12 @@
      */
     private long tryIncReaderOverflow(long s) {
         // assert (s & ABITS) >= RFULL;
-        if ((s & ABITS) == RFULL) {
-            if (casState(s, s | RBITS)) {
-                ++readerOverflow;
-                STATE.setVolatile(this, s);
-                return s;
-            }
+        if ((s & ABITS) != RFULL)
+            Thread.onSpinWait();
+        else if (casState(s, s | RBITS)) {
+            ++readerOverflow;
+            return state = s;
         }
-        else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
-            Thread.yield();
-        else
-            Thread.onSpinWait();
         return 0L;
     }
 
@@ -1192,153 +1133,132 @@
      */
     private long tryDecReaderOverflow(long s) {
         // assert (s & ABITS) >= RFULL;
-        if ((s & ABITS) == RFULL) {
-            if (casState(s, s | RBITS)) {
-                int r; long next;
-                if ((r = readerOverflow) > 0) {
-                    readerOverflow = r - 1;
-                    next = s;
-                }
-                else
-                    next = s - RUNIT;
-                STATE.setVolatile(this, next);
-                return next;
+        if ((s & ABITS) != RFULL)
+            Thread.onSpinWait();
+        else if (casState(s, s | RBITS)) {
+            int r; long nextState;
+            if ((r = readerOverflow) > 0) {
+                readerOverflow = r - 1;
+                nextState = s;
             }
+            else
+                nextState = s - RUNIT;
+            return state = nextState;
         }
-        else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
-            Thread.yield();
-        else
-            Thread.onSpinWait();
         return 0L;
     }
 
+    // release methods
+
     /**
-     * Wakes up the successor of h (normally whead). This is normally
-     * just h.next, but may require traversal from wtail if next
-     * pointers are lagging. This may fail to wake up an acquiring
-     * thread when one or more have been cancelled, but the cancel
-     * methods themselves provide extra safeguards to ensure liveness.
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
      */
-    private void release(WNode h) {
-        if (h != null) {
-            WNode q; Thread w;
-            WSTATUS.compareAndSet(h, WAITING, 0);
-            if ((q = h.next) == null || q.status == CANCELLED) {
-                for (WNode t = wtail; t != null && t != h; t = t.prev)
-                    if (t.status <= 0)
-                        q = t;
-            }
-            if (q != null && (w = q.thread) != null)
-                LockSupport.unpark(w);
+    static final void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status > 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
         }
     }
 
     /**
-     * See above for explanation.
+     * Removes and unparks all cowaiters of node, if it exists.
+     */
+    private static void signalCowaiters(ReaderNode node) {
+        if (node != null) {
+            for (ReaderNode c; (c = node.cowaiters) != null; ) {
+                if (node.casCowaiters(c, c.cowaiters))
+                    LockSupport.unpark(c.waiter);
+            }
+        }
+    }
+
+    // queue link methods
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new WriterNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
+
+    /**
+     * For explanation, see above and AbstractQueuedSynchronizer
+     * internal documentation.
      *
      * @param interruptible true if should check interrupts and if so
      * return INTERRUPTED
-     * @param deadline if nonzero, the System.nanoTime value to timeout
-     * at (and return zero)
+     * @param timed if true use timed waits
+     * @param time the System.nanoTime value to timeout at (and return zero)
      * @return next state, or INTERRUPTED
      */
-    private long acquireWrite(boolean interruptible, long deadline) {
-        WNode node = null, p;
-        for (int spins = -1;;) { // spin while enqueuing
-            long m, s, ns;
-            if ((m = (s = state) & ABITS) == 0L) {
-                if ((ns = tryWriteLock(s)) != 0L)
-                    return ns;
+    private long acquireWrite(boolean interruptible, boolean timed, long time) {
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        WriterNode node = null;
+        Node pred = null;
+        for (long s, nextState;;) {
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
             }
-            else if (spins < 0)
-                spins = (m == WBIT && wtail == whead) ? SPINS : 0;
-            else if (spins > 0) {
+            if ((first || pred == null) && ((s = state) & ABITS) == 0L &&
+                casState(s, nextState = s | WBIT)) {
+                U.storeStoreFence();
+                if (first) {
+                    node.prev = null;
+                    head = node;
+                    pred.next = null;
+                    node.waiter = null;
+                    if (interrupted)
+                        Thread.currentThread().interrupt();
+                }
+                return nextState;
+            } else if (node == null) {          // retry before enqueuing
+                node = new WriterNode();
+            } else if (pred == null) {          // try to enqueue
+                Node t = tail;
+                node.setPrevRelaxed(t);
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {   // reduce unfairness
                 --spins;
                 Thread.onSpinWait();
-            }
-            else if ((p = wtail) == null) { // initialize queue
-                WNode hd = new WNode(WMODE, null);
-                if (WHEAD.weakCompareAndSet(this, null, hd))
-                    wtail = hd;
-            }
-            else if (node == null)
-                node = new WNode(WMODE, p);
-            else if (node.prev != p)
-                node.prev = p;
-            else if (WTAIL.weakCompareAndSet(this, p, node)) {
-                p.next = node;
-                break;
+            } else if (node.status == 0) {      // enable signal
+                if (node.waiter == null)
+                    node.waiter = Thread.currentThread();
+                node.status = WAITING;
+            } else {
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
             }
         }
-
-        boolean wasInterrupted = false;
-        for (int spins = -1;;) {
-            WNode h, np, pp; int ps;
-            if ((h = whead) == p) {
-                if (spins < 0)
-                    spins = HEAD_SPINS;
-                else if (spins < MAX_HEAD_SPINS)
-                    spins <<= 1;
-                for (int k = spins; k > 0; --k) { // spin at head
-                    long s, ns;
-                    if (((s = state) & ABITS) == 0L) {
-                        if ((ns = tryWriteLock(s)) != 0L) {
-                            whead = node;
-                            node.prev = null;
-                            if (wasInterrupted)
-                                Thread.currentThread().interrupt();
-                            return ns;
-                        }
-                    }
-                    else
-                        Thread.onSpinWait();
-                }
-            }
-            else if (h != null) { // help release stale waiters
-                WNode c; Thread w;
-                while ((c = h.cowait) != null) {
-                    if (WCOWAIT.weakCompareAndSet(h, c, c.cowait) &&
-                        (w = c.thread) != null)
-                        LockSupport.unpark(w);
-                }
-            }
-            if (whead == h) {
-                if ((np = node.prev) != p) {
-                    if (np != null)
-                        (p = np).next = node;   // stale
-                }
-                else if ((ps = p.status) == 0)
-                    WSTATUS.compareAndSet(p, 0, WAITING);
-                else if (ps == CANCELLED) {
-                    if ((pp = p.prev) != null) {
-                        node.prev = pp;
-                        pp.next = node;
-                    }
-                }
-                else {
-                    long time; // 0 argument to park means no timeout
-                    if (deadline == 0L)
-                        time = 0L;
-                    else if ((time = deadline - System.nanoTime()) <= 0L)
-                        return cancelWaiter(node, node, false);
-                    Thread wt = Thread.currentThread();
-                    node.thread = wt;
-                    if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
-                        whead == h && node.prev == p) {
-                        if (time == 0L)
-                            LockSupport.park(this);
-                        else
-                            LockSupport.parkNanos(this, time);
-                    }
-                    node.thread = null;
-                    if (Thread.interrupted()) {
-                        if (interruptible)
-                            return cancelWaiter(node, node, true);
-                        wasInterrupted = true;
-                    }
-                }
-            }
-        }
+        return cancelAcquire(node, interrupted);
     }
 
     /**
@@ -1346,182 +1266,178 @@
      *
      * @param interruptible true if should check interrupts and if so
      * return INTERRUPTED
-     * @param deadline if nonzero, the System.nanoTime value to timeout
-     * at (and return zero)
+     * @param timed if true use timed waits
+     * @param time the System.nanoTime value to timeout at (and return zero)
      * @return next state, or INTERRUPTED
      */
-    private long acquireRead(boolean interruptible, long deadline) {
-        boolean wasInterrupted = false;
-        WNode node = null, p;
-        for (int spins = -1;;) {
-            WNode h;
-            if ((h = whead) == (p = wtail)) {
-                for (long m, s, ns;;) {
-                    if ((m = (s = state) & ABITS) < RFULL ?
-                        casState(s, ns = s + RUNIT) :
-                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
-                        if (wasInterrupted)
-                            Thread.currentThread().interrupt();
-                        return ns;
+    private long acquireRead(boolean interruptible, boolean timed, long time) {
+        boolean interrupted = false;
+        ReaderNode node = null;
+        /*
+         * Loop:
+         *   if empty, try to acquire
+         *   if tail is Reader, try to cowait; restart if leader stale or cancels
+         *   else try to create and enqueue node, and wait in 2nd loop below
+         */
+        for (;;) {
+            ReaderNode leader; long nextState;
+            Node tailPred = null, t = tail;
+            if ((t == null || (tailPred = t.prev) == null) &&
+                (nextState = tryAcquireRead()) != 0L) // try now if empty
+                return nextState;
+            else if (t == null)
+                tryInitializeHead();
+            else if (tailPred == null || !(t instanceof ReaderNode)) {
+                if (node == null)
+                    node = new ReaderNode();
+                if (tail == t) {
+                    node.setPrevRelaxed(t);
+                    if (casTail(t, node)) {
+                        t.next = node;
+                        break; // node is leader; wait in loop below
                     }
-                    else if (m >= WBIT) {
-                        if (spins > 0) {
-                            --spins;
-                            Thread.onSpinWait();
-                        }
-                        else {
-                            if (spins == 0) {
-                                WNode nh = whead, np = wtail;
-                                if ((nh == h && np == p) || (h = nh) != (p = np))
-                                    break;
-                            }
-                            spins = SPINS;
-                        }
+                    node.setPrevRelaxed(null);
+                }
+            } else if ((leader = (ReaderNode)t) == tail) { // try to cowait
+                for (boolean attached = false;;) {
+                    if (leader.status < 0 || leader.prev == null)
+                        break;
+                    else if (node == null)
+                        node = new ReaderNode();
+                    else if (node.waiter == null)
+                        node.waiter = Thread.currentThread();
+                    else if (!attached) {
+                        ReaderNode c = leader.cowaiters;
+                        node.setCowaitersRelaxed(c);
+                        attached = leader.casCowaiters(c, node);
+                        if (!attached)
+                            node.setCowaitersRelaxed(null);
+                    } else {
+                        long nanos = 0L;
+                        if (!timed)
+                            LockSupport.park(this);
+                        else if ((nanos = time - System.nanoTime()) > 0L)
+                            LockSupport.parkNanos(this, nanos);
+                        interrupted |= Thread.interrupted();
+                        if ((interrupted && interruptible) ||
+                            (timed && nanos <= 0L))
+                            return cancelCowaiter(node, leader, interrupted);
                     }
                 }
-            }
-            if (p == null) { // initialize queue
-                WNode hd = new WNode(WMODE, null);
-                if (WHEAD.weakCompareAndSet(this, null, hd))
-                    wtail = hd;
-            }
-            else if (node == null)
-                node = new WNode(RMODE, p);
-            else if (h == p || p.mode != RMODE) {
-                if (node.prev != p)
-                    node.prev = p;
-                else if (WTAIL.weakCompareAndSet(this, p, node)) {
-                    p.next = node;
-                    break;
-                }
-            }
-            else if (!WCOWAIT.compareAndSet(p, node.cowait = p.cowait, node))
-                node.cowait = null;
-            else {
-                for (;;) {
-                    WNode pp, c; Thread w;
-                    if ((h = whead) != null && (c = h.cowait) != null &&
-                        WCOWAIT.compareAndSet(h, c, c.cowait) &&
-                        (w = c.thread) != null) // help release
-                        LockSupport.unpark(w);
-                    if (Thread.interrupted()) {
-                        if (interruptible)
-                            return cancelWaiter(node, p, true);
-                        wasInterrupted = true;
-                    }
-                    if (h == (pp = p.prev) || h == p || pp == null) {
-                        long m, s, ns;
-                        do {
-                            if ((m = (s = state) & ABITS) < RFULL ?
-                                casState(s, ns = s + RUNIT) :
-                                (m < WBIT &&
-                                 (ns = tryIncReaderOverflow(s)) != 0L)) {
-                                if (wasInterrupted)
-                                    Thread.currentThread().interrupt();
-                                return ns;
-                            }
-                        } while (m < WBIT);
-                    }
-                    if (whead == h && p.prev == pp) {
-                        long time;
-                        if (pp == null || h == p || p.status > 0) {
-                            node = null; // throw away
-                            break;
-                        }
-                        if (deadline == 0L)
-                            time = 0L;
-                        else if ((time = deadline - System.nanoTime()) <= 0L) {
-                            if (wasInterrupted)
-                                Thread.currentThread().interrupt();
-                            return cancelWaiter(node, p, false);
-                        }
-                        Thread wt = Thread.currentThread();
-                        node.thread = wt;
-                        if ((h != pp || (state & ABITS) == WBIT) &&
-                            whead == h && p.prev == pp) {
-                            if (time == 0L)
-                                LockSupport.park(this);
-                            else
-                                LockSupport.parkNanos(this, time);
-                        }
-                        node.thread = null;
-                    }
-                }
+                if (node != null)
+                    node.waiter = null;
+                long ns = tryAcquireRead();
+                signalCowaiters(leader);
+                if (interrupted)
+                    Thread.currentThread().interrupt();
+                if (ns != 0L)
+                    return ns;
+                else
+                    node = null; // restart if stale, missed, or leader cancelled
             }
         }
 
-        for (int spins = -1;;) {
-            WNode h, np, pp; int ps;
-            if ((h = whead) == p) {
-                if (spins < 0)
-                    spins = HEAD_SPINS;
-                else if (spins < MAX_HEAD_SPINS)
-                    spins <<= 1;
-                for (int k = spins;;) { // spin at head
-                    long m, s, ns;
-                    if ((m = (s = state) & ABITS) < RFULL ?
-                        casState(s, ns = s + RUNIT) :
-                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
-                        WNode c; Thread w;
-                        whead = node;
-                        node.prev = null;
-                        while ((c = node.cowait) != null) {
-                            if (WCOWAIT.compareAndSet(node, c, c.cowait) &&
-                                (w = c.thread) != null)
-                                LockSupport.unpark(w);
-                        }
-                        if (wasInterrupted)
-                            Thread.currentThread().interrupt();
-                        return ns;
-                    }
-                    else if (m >= WBIT && --k <= 0)
-                        break;
-                    else
-                        Thread.onSpinWait();
+        // node is leader of a cowait group; almost same as acquireWrite
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean first = false;
+        Node pred = null;
+        for (long nextState;;) {
+            if (!first && (pred = node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
                 }
             }
-            else if (h != null) {
-                WNode c; Thread w;
-                while ((c = h.cowait) != null) {
-                    if (WCOWAIT.compareAndSet(h, c, c.cowait) &&
-                        (w = c.thread) != null)
-                        LockSupport.unpark(w);
-                }
-            }
-            if (whead == h) {
-                if ((np = node.prev) != p) {
-                    if (np != null)
-                        (p = np).next = node;   // stale
-                }
-                else if ((ps = p.status) == 0)
-                    WSTATUS.compareAndSet(p, 0, WAITING);
-                else if (ps == CANCELLED) {
-                    if ((pp = p.prev) != null) {
-                        node.prev = pp;
-                        pp.next = node;
-                    }
+            if ((first || pred == null) &&
+                (nextState = tryAcquireRead()) != 0L) {
+                if (first) {
+                    node.prev = null;
+                    head = node;
+                    pred.next = null;
+                    node.waiter = null;
                 }
-                else {
-                    long time;
-                    if (deadline == 0L)
-                        time = 0L;
-                    else if ((time = deadline - System.nanoTime()) <= 0L)
-                        return cancelWaiter(node, node, false);
-                    Thread wt = Thread.currentThread();
-                    node.thread = wt;
-                    if (p.status < 0 &&
-                        (p != h || (state & ABITS) == WBIT) &&
-                        whead == h && node.prev == p) {
-                            if (time == 0L)
-                                LockSupport.park(this);
-                            else
-                                LockSupport.parkNanos(this, time);
+                signalCowaiters(node);
+                if (interrupted)
+                    Thread.currentThread().interrupt();
+                return nextState;
+            } else if (first && spins != 0) {
+                --spins;
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                if (node.waiter == null)
+                    node.waiter = Thread.currentThread();
+                node.status = WAITING;
+            } else {
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted);
+    }
+
+    // Cancellation support
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found. Unparks nodes that may have been
+     * relinked to be next eligible acquirer.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
                     }
-                    node.thread = null;
-                    if (Thread.interrupted()) {
-                        if (interruptible)
-                            return cancelWaiter(node, node, true);
-                        wasInterrupted = true;
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p && q.status >= 0) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
+            }
+        }
+    }
+
+    /**
+     * If leader exists, possibly repeatedly traverses cowaiters,
+     * unsplicing the given cancelled node until not found.
+     */
+    private void unlinkCowaiter(ReaderNode node, ReaderNode leader) {
+        if (leader != null) {
+            while (leader.prev != null && leader.status >= 0) {
+                for (ReaderNode p = leader, q; ; p = q) {
+                    if ((q = p.cowaiters) == null)
+                        return;
+                    if (q == node) {
+                        p.casCowaiters(q, q.cowaiters);
+                        break;  // recheck even if succeeded
                     }
                 }
             }
@@ -1530,105 +1446,53 @@
 
     /**
      * If node non-null, forces cancel status and unsplices it from
-     * queue if possible and wakes up any cowaiters (of the node, or
-     * group, as applicable), and in any case helps release current
-     * first waiter if lock is free. (Calling with null arguments
-     * serves as a conditional form of release, which is not currently
-     * needed but may be needed under possible future cancellation
-     * policies). This is a variant of cancellation methods in
-     * AbstractQueuedSynchronizer (see its detailed explanation in AQS
-     * internal documentation).
+     * queue, wakes up any cowaiters, and possibly wakes up successor
+     * to recheck status.
      *
-     * @param node if non-null, the waiter
-     * @param group either node or the group node is cowaiting with
+     * @param node the waiter (may be null if not yet enqueued)
      * @param interrupted if already interrupted
      * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
      */
-    private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
-        if (node != null && group != null) {
-            Thread w;
+    private long cancelAcquire(Node node, boolean interrupted) {
+        if (node != null) {
+            node.waiter = null;
             node.status = CANCELLED;
-            // unsplice cancelled nodes from group
-            for (WNode p = group, q; (q = p.cowait) != null;) {
-                if (q.status == CANCELLED) {
-                    WCOWAIT.compareAndSet(p, q, q.cowait);
-                    p = group; // restart
-                }
-                else
-                    p = q;
-            }
-            if (group == node) {
-                for (WNode r = group.cowait; r != null; r = r.cowait) {
-                    if ((w = r.thread) != null)
-                        LockSupport.unpark(w); // wake up uncancelled co-waiters
-                }
-                for (WNode pred = node.prev; pred != null; ) { // unsplice
-                    WNode succ, pp;        // find valid successor
-                    while ((succ = node.next) == null ||
-                           succ.status == CANCELLED) {
-                        WNode q = null;    // find successor the slow way
-                        for (WNode t = wtail; t != null && t != node; t = t.prev)
-                            if (t.status != CANCELLED)
-                                q = t;     // don't link if succ cancelled
-                        if (succ == q ||   // ensure accurate successor
-                            WNEXT.compareAndSet(node, succ, succ = q)) {
-                            if (succ == null && node == wtail)
-                                WTAIL.compareAndSet(this, node, pred);
-                            break;
-                        }
-                    }
-                    if (pred.next == node) // unsplice pred link
-                        WNEXT.compareAndSet(pred, node, succ);
-                    if (succ != null && (w = succ.thread) != null) {
-                        // wake up succ to observe new pred
-                        succ.thread = null;
-                        LockSupport.unpark(w);
-                    }
-                    if (pred.status != CANCELLED || (pp = pred.prev) == null)
-                        break;
-                    node.prev = pp;        // repeat if new pred wrong/cancelled
-                    WNEXT.compareAndSet(pp, pred, succ);
-                    pred = pp;
-                }
-            }
-        }
-        WNode h; // Possibly release first waiter
-        while ((h = whead) != null) {
-            long s; WNode q; // similar to release() but check eligibility
-            if ((q = h.next) == null || q.status == CANCELLED) {
-                for (WNode t = wtail; t != null && t != h; t = t.prev)
-                    if (t.status <= 0)
-                        q = t;
-            }
-            if (h == whead) {
-                if (q != null && h.status == 0 &&
-                    ((s = state) & ABITS) != WBIT && // waiter is eligible
-                    (s == 0L || q.mode == RMODE))
-                    release(h);
-                break;
-            }
+            cleanQueue();
+            if (node instanceof ReaderNode)
+                signalCowaiters((ReaderNode)node);
         }
         return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATE;
-    private static final VarHandle WHEAD;
-    private static final VarHandle WTAIL;
-    private static final VarHandle WNEXT;
-    private static final VarHandle WSTATUS;
-    private static final VarHandle WCOWAIT;
+    /**
+     * If node non-null, forces cancel status and unsplices from
+     * leader's cowaiters list unless/until it is also cancelled.
+     *
+     * @param node if non-null, the waiter
+     * @param leader if non-null, the node heading cowaiters list
+     * @param interrupted if already interrupted
+     * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
+     */
+    private long cancelCowaiter(ReaderNode node, ReaderNode leader,
+                                boolean interrupted) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            unlinkCowaiter(node, leader);
+        }
+        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
+    }
+
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(StampedLock.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(StampedLock.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(StampedLock.class, "tail");
+
     static {
-        try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(StampedLock.class, "state", long.class);
-            WHEAD = l.findVarHandle(StampedLock.class, "whead", WNode.class);
-            WTAIL = l.findVarHandle(StampedLock.class, "wtail", WNode.class);
-            WSTATUS = l.findVarHandle(WNode.class, "status", int.class);
-            WNEXT = l.findVarHandle(WNode.class, "next", WNode.class);
-            WCOWAIT = l.findVarHandle(WNode.class, "cowait", WNode.class);
-        } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
-        }
+        Class<?> ensureLoaded = LockSupport.class;
     }
 }
--- a/src/java.base/share/classes/java/util/concurrent/package-info.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/package-info.java	Sun Sep 15 13:41:19 2019 +0200
@@ -226,9 +226,8 @@
  *
  * <h2 id="MemoryVisibility">Memory Consistency Properties</h2>
  *
- * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4.5">
  * Chapter 17 of
- * <cite>The Java&trade; Language Specification</cite></a> defines the
+ * <cite>The Java&trade; Language Specification</cite> defines the
  * <i>happens-before</i> relation on memory operations such as reads and
  * writes of shared variables.  The results of a write by one thread are
  * guaranteed to be visible to a read by another thread only if the write
@@ -302,6 +301,8 @@
  *
  * </ul>
  *
+ * @jls 17.4.5 Happens-before Order
+ *
  * @since 1.5
  */
 package java.util.concurrent;
--- a/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp	Sat Sep 14 13:18:20 2019 +0200
+++ b/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp	Sun Sep 15 13:41:19 2019 +0200
@@ -218,7 +218,7 @@
 static BOOLEAN
 has_oid(gss_const_OID_set set, gss_const_OID oid)
 {
-    for (int i = 0; i < set->count; i++) {
+    for (size_t i = 0; i < set->count; i++) {
         if (is_same_oid(&set->elements[i], oid)) {
             return TRUE;
         }
@@ -257,7 +257,7 @@
             return;
         }
         PP("gss_OID_set.count is %d", (int)mechs->count);
-        for (int i = 0; i < mechs->count; i++) {
+        for (size_t i = 0; i < mechs->count; i++) {
             show_oid(&mechs->elements[i]);
         }
     }
@@ -1584,7 +1584,7 @@
     if (set == NULL || *set == GSS_C_NO_OID_SET) {
         return GSS_S_COMPLETE;
     }
-    for (int i = 0; i < (*set)->count; i++) {
+    for (size_t i = 0; i < (*set)->count; i++) {
         delete[] (*set)->elements[i].elements;
     }
     delete[] (*set)->elements;
--- a/test/jdk/java/util/Map/Get.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/Map/Get.java	Sun Sep 15 13:41:19 2019 +0200
@@ -120,8 +120,8 @@
     //--------------------- Infrastructure ---------------------------
     static volatile int passed = 0, failed = 0;
     static void pass() { passed++; }
-    static void fail() { failed++; (new Error("Failure")).printStackTrace(System.err); }
-    static void fail(String msg) { failed++; (new Error("Failure: " + msg)).printStackTrace(System.err); }
+    static void fail() { failed++; new Error("Failure").printStackTrace(System.err); }
+    static void fail(String msg) { failed++; new Error("Failure: " + msg).printStackTrace(System.err); }
     static void unexpected(String msg, Throwable t) { System.err.println("Unexpected: " + msg); unexpected(t); }
     static void unexpected(Throwable t) { failed++; t.printStackTrace(System.err); }
     static void check(boolean cond) { if (cond) pass(); else fail(); }
--- a/test/jdk/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -34,6 +34,7 @@
 /*
  * @test
  * @bug 6805775 6815766
+ * @library /test/lib
  * @run main OfferDrainToLoops 100
  * @summary Test concurrent offer vs. drainTo
  */
@@ -47,10 +48,12 @@
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.LinkedTransferQueue;
 import java.util.concurrent.atomic.AtomicLong;
+import jdk.test.lib.Utils;
 
 @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
 public class OfferDrainToLoops {
-    final long testDurationMillisDefault = 10L * 1000L;
+    static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
+    final long testDurationMillisDefault = 10_000L;
     final long testDurationMillis;
 
     OfferDrainToLoops(String[] args) {
@@ -76,7 +79,6 @@
         System.out.println(q.getClass().getSimpleName());
         final long testDurationNanos = testDurationMillis * 1000L * 1000L;
         final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
-        final long timeoutMillis = 10L * 1000L;
         final SplittableRandom rnd = new SplittableRandom();
 
         // Poor man's bounded buffer.
@@ -155,13 +157,13 @@
                 }}};
 
         for (Thread thread : new Thread[] { offerer, drainer, scanner }) {
-            thread.join(timeoutMillis + testDurationMillis);
+            thread.join(LONG_DELAY_MS + testDurationMillis);
             if (thread.isAlive()) {
                 System.err.printf("Hung thread: %s%n", thread.getName());
                 failed++;
                 for (StackTraceElement e : thread.getStackTrace())
                     System.err.println(e);
-                thread.join(timeoutMillis);
+                thread.join(LONG_DELAY_MS);
             }
         }
     }
--- a/test/jdk/java/util/concurrent/ConcurrentHashMap/MapCheck.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/MapCheck.java	Sun Sep 15 13:41:19 2019 +0200
@@ -537,7 +537,7 @@
         static void printStats() {
             for (Iterator it = accum.entrySet().iterator(); it.hasNext(); ) {
                 Map.Entry e = (Map.Entry)(it.next());
-                Stats stats = ((Stats)(e.getValue()));
+                Stats stats = (Stats)(e.getValue());
                 int n = stats.number;
                 double t;
                 if (n > 0)
--- a/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -99,8 +99,8 @@
             nops = Integer.parseInt(args[5]);
 
         // normalize probabilities wrt random number generator
-        removesPerMaxRandom = (int)(((double)premove/100.0 * 0x7FFFFFFFL));
-        insertsPerMaxRandom = (int)(((double)pinsert/100.0 * 0x7FFFFFFFL));
+        removesPerMaxRandom = (int)((double)premove/100.0 * 0x7FFFFFFFL);
+        insertsPerMaxRandom = (int)((double)pinsert/100.0 * 0x7FFFFFFFL);
 
         System.out.print("Class: " + mapClass.getName());
         System.out.print(" threads: " + maxThreads);
@@ -172,7 +172,7 @@
         long time = timer.getTime();
         long tpo = time / (i * (long)nops);
         System.out.print(LoopHelpers.rightJustify(tpo) + " ns per op");
-        double secs = (double)(time) / 1000000000.0;
+        double secs = (double)time / 1000000000.0;
         System.out.println("\t " + secs + "s run time");
         map.clear();
     }
--- a/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java	Sun Sep 15 13:41:19 2019 +0200
@@ -24,37 +24,40 @@
 /*
  * @test
  * @bug 4486658 8010293
- * @summary thread safety of toArray methods of subCollections
+ * @summary thread safety of toArray methods of collection views
  * @author Martin Buchholz
  */
 
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
 public class ToArray {
 
     public static void main(String[] args) throws Throwable {
-        // Execute a number of times to increase the probability of
-        // failure if there is an issue
-        for (int i = 0; i < 16; i++) {
+        final int runsPerTest = Integer.getInteger("jsr166.runsPerTest", 1);
+        final int reps = 10 * runsPerTest;
+        for (int i = reps; i--> 0; )
             executeTest();
-        }
     }
 
     static void executeTest() throws Throwable {
-        final Throwable[] throwable = new Throwable[1];
         final ConcurrentHashMap<Integer, Integer> m = new ConcurrentHashMap<>();
-
-        // Number of workers equal to the number of processors
-        // Each worker will put globally unique keys into the map
-        final int nWorkers = Runtime.getRuntime().availableProcessors();
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        final int nCPU = Runtime.getRuntime().availableProcessors();
+        final int minWorkers = 2;
+        final int maxWorkers = Math.max(minWorkers, Math.min(32, nCPU));
+        final int nWorkers = rnd.nextInt(minWorkers, maxWorkers + 1);
         final int sizePerWorker = 1024;
         final int maxSize = nWorkers * sizePerWorker;
 
-        // The foreman keeps checking that the size of the arrays
-        // obtained from the key and value sets is never less than the
-        // previously observed size and is never greater than the maximum size
+        // The foreman busy-checks that the size of the arrays obtained
+        // from the keys and values views grows monotonically until it
+        // reaches the maximum size.
+
         // NOTE: these size constraints are not specific to toArray and are
         // applicable to any form of traversal of the collection views
         CompletableFuture<?> foreman = CompletableFuture.runAsync(new Runnable() {
@@ -62,44 +65,37 @@
 
             private boolean checkProgress(Object[] a) {
                 int size = a.length;
-                if (size < prevSize) throw new RuntimeException("WRONG WAY");
-                if (size > maxSize) throw new RuntimeException("OVERSHOOT");
-                if (size == maxSize) return true;
+                if (size < prevSize || size > maxSize)
+                    throw new AssertionError(
+                        String.format("prevSize=%d size=%d maxSize=%d",
+                                      prevSize, size, maxSize));
                 prevSize = size;
-                return false;
+                return size == maxSize;
             }
 
-            @Override
             public void run() {
-                try {
-                    Integer[] empty = new Integer[0];
-                    while (true) {
-                        if (checkProgress(m.values().toArray())) return;
-                        if (checkProgress(m.keySet().toArray())) return;
-                        if (checkProgress(m.values().toArray(empty))) return;
-                        if (checkProgress(m.keySet().toArray(empty))) return;
-                    }
-                }
-                catch (Throwable t) {
-                    throwable[0] = t;
-                }
+                Integer[] empty = new Integer[0];
+                for (;;)
+                    if (checkProgress(m.values().toArray())
+                        & checkProgress(m.keySet().toArray())
+                        & checkProgress(m.values().toArray(empty))
+                        & checkProgress(m.keySet().toArray(empty)))
+                        return;
             }
         });
 
-        // Create workers
-        // Each worker will put globally unique keys into the map
-        CompletableFuture<?>[] workers = IntStream.range(0, nWorkers).
-                mapToObj(w -> CompletableFuture.runAsync(() -> {
-                    for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++)
-                        m.put(o + i, i);
-                })).
-                toArray(CompletableFuture<?>[]::new);
+        // Each worker puts globally unique keys into the map
+        List<CompletableFuture<?>> workers =
+            IntStream.range(0, nWorkers)
+            .mapToObj(w -> (Runnable) () -> {
+                for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++)
+                    m.put(o + i, i);
+            })
+            .map(CompletableFuture::runAsync)
+            .collect(Collectors.toList());
 
-        // Wait for workers and then foreman to complete
-        CompletableFuture.allOf(workers).join();
+        // Wait for workers and foreman to complete
+        workers.forEach(CompletableFuture<?>::join);
         foreman.join();
-
-        if (throwable[0] != null)
-            throw throwable[0];
     }
 }
--- a/test/jdk/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -25,7 +25,8 @@
  * @test
  * @bug 6316155 6595669 6871697 6868712
  * @summary Test concurrent offer vs. remove
- * @run main OfferRemoveLoops 300
+ * @library /test/lib
+ * @run main OfferRemoveLoops 100
  * @author Martin Buchholz
  */
 
@@ -43,10 +44,12 @@
 import java.util.concurrent.LinkedTransferQueue;
 import java.util.concurrent.PriorityBlockingQueue;
 import java.util.concurrent.Semaphore;
+import jdk.test.lib.Utils;
 
 @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
 public class OfferRemoveLoops {
-    final long testDurationMillisDefault = 10L * 1000L;
+    static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
+    final long testDurationMillisDefault = 10_000L;
     final long testDurationMillis;
 
     OfferRemoveLoops(String[] args) {
@@ -75,7 +78,6 @@
         System.err.println(q.getClass().getSimpleName());
         final long testDurationNanos = testDurationMillis * 1000L * 1000L;
         final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
-        final long timeoutMillis = 10L * 1000L;
         final int maxChunkSize = 1042;
         final int maxQueueSize = 10 * maxChunkSize;
         final CountDownLatch done = new CountDownLatch(3);
@@ -156,7 +158,7 @@
                 done.countDown();
             }};
 
-        if (! done.await(timeoutMillis + testDurationMillis, MILLISECONDS)) {
+        if (! done.await(LONG_DELAY_MS + testDurationMillis, MILLISECONDS)) {
             for (Thread thread : new Thread[] { offerer, remover, scanner }) {
                 if (thread.isAlive()) {
                     System.err.printf("Hung thread: %s%n", thread.getName());
--- a/test/jdk/java/util/concurrent/CountDownLatch/Basic.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/CountDownLatch/Basic.java	Sun Sep 15 13:41:19 2019 +0200
@@ -23,70 +23,57 @@
 
 /*
  * @test
- * @bug 6332435
+ * @bug 6332435 8221168
  * @summary Basic tests for CountDownLatch
  * @library /test/lib
  * @author Seetharam Avadhanam, Martin Buchholz
  */
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
 import jdk.test.lib.Utils;
 
 public class Basic {
     static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
 
-    interface AwaiterFactory {
-        Awaiter getAwaiter();
-    }
-
     abstract static class Awaiter extends Thread {
-        private volatile Throwable result = null;
-        protected void result(Throwable result) { this.result = result; }
-        public Throwable result() { return this.result; }
-    }
-
-    private void toTheStartingGate(CountDownLatch gate) {
-        try {
-            gate.await();
-        }
-        catch (Throwable t) { fail(t); }
+        volatile Throwable exception;
+        volatile boolean interrupted;
+        abstract void realRun() throws Exception;
+        public final void run() {
+            try { realRun(); }
+            catch (Throwable ex) { exception = ex; }
+            interrupted = Thread.interrupted();
+        };
     }
 
-    private Awaiter awaiter(final CountDownLatch latch,
-                            final CountDownLatch gate) {
-        return new Awaiter() { public void run() {
-            System.out.println("without millis: " + latch.toString());
-            gate.countDown();
-
-            try {
+    static Awaiter awaiter(CountDownLatch latch,
+                           CountDownLatch gate) {
+        return new Awaiter() {
+            public void realRun() throws InterruptedException {
+                gate.countDown();
                 latch.await();
-                System.out.println("without millis - ComingOut");
-            }
-            catch (Throwable result) { result(result); }}};
+            }};
     }
 
-    private Awaiter awaiter(final CountDownLatch latch,
-                            final CountDownLatch gate,
-                            final long millis) {
-        return new Awaiter() { public void run() {
-            System.out.println("with millis: "+latch.toString());
-            gate.countDown();
-
-            try {
-                latch.await(millis, TimeUnit.MILLISECONDS);
-                System.out.println("with millis - ComingOut");
-            }
-            catch (Throwable result) { result(result); }}};
+    static Awaiter awaiter(CountDownLatch latch,
+                           CountDownLatch gate,
+                           long timeoutMillis) {
+        return new Awaiter() {
+            public void realRun() throws InterruptedException {
+                gate.countDown();
+                latch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+            }};
     }
 
-    AwaiterFactory awaiterFactory(CountDownLatch latch, CountDownLatch gate) {
-        return () -> awaiter(latch, gate);
-    }
-
-    AwaiterFactory timedAwaiterFactory(CountDownLatch latch, CountDownLatch gate) {
-        return () -> awaiter(latch, gate, LONG_DELAY_MS);
+    static Supplier<Awaiter> randomAwaiterSupplier(
+            CountDownLatch latch, CountDownLatch gate) {
+        return () -> (ThreadLocalRandom.current().nextBoolean())
+            ? awaiter(latch, gate)
+            : awaiter(latch, gate, LONG_DELAY_MS);
     }
 
     //----------------------------------------------------------------
@@ -94,28 +81,24 @@
     //----------------------------------------------------------------
     public static void normalUse() throws Throwable {
         int count = 0;
-        Basic test = new Basic();
         CountDownLatch latch = new CountDownLatch(3);
         Awaiter[] a = new Awaiter[12];
 
         for (int i = 0; i < 3; i++) {
             CountDownLatch gate = new CountDownLatch(4);
-            AwaiterFactory factory1 = test.awaiterFactory(latch, gate);
-            AwaiterFactory factory2 = test.timedAwaiterFactory(latch, gate);
-            a[count] = factory1.getAwaiter(); a[count++].start();
-            a[count] = factory1.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
-            test.toTheStartingGate(gate);
-            System.out.println("Main Thread: " + latch.toString());
+            Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            gate.await();
             latch.countDown();
             checkCount(latch, 2-i);
         }
-        for (int i = 0; i < 12; i++)
-            a[i].join();
-
-        for (int i = 0; i < 12; i++)
-            checkResult(a[i], null);
+        for (Awaiter awaiter : a)
+            awaiter.join();
+        for (Awaiter awaiter : a)
+            checkException(awaiter, null);
     }
 
     //----------------------------------------------------------------
@@ -123,38 +106,38 @@
     //----------------------------------------------------------------
     public static void threadInterrupted() throws Throwable {
         int count = 0;
-        Basic test = new Basic();
         CountDownLatch latch = new CountDownLatch(3);
         Awaiter[] a = new Awaiter[12];
 
         for (int i = 0; i < 3; i++) {
             CountDownLatch gate = new CountDownLatch(4);
-            AwaiterFactory factory1 = test.awaiterFactory(latch, gate);
-            AwaiterFactory factory2 = test.timedAwaiterFactory(latch, gate);
-            a[count] = factory1.getAwaiter(); a[count++].start();
-            a[count] = factory1.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
+            Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            gate.await();
             a[count-1].interrupt();
-            test.toTheStartingGate(gate);
-            System.out.println("Main Thread: " + latch.toString());
             latch.countDown();
             checkCount(latch, 2-i);
         }
-        for (int i = 0; i < 12; i++)
-            a[i].join();
-
-        for (int i = 0; i < 12; i++)
-            checkResult(a[i],
-                        (i % 4) == 3 ? InterruptedException.class : null);
+        for (Awaiter awaiter : a)
+            awaiter.join();
+        for (int i = 0; i < a.length; i++) {
+            Awaiter awaiter = a[i];
+            Throwable ex = awaiter.exception;
+            if ((i % 4) == 3 && !awaiter.interrupted)
+                checkException(awaiter, InterruptedException.class);
+            else
+                checkException(awaiter, null);
+        }
     }
 
     //----------------------------------------------------------------
     // One thread timed out
     //----------------------------------------------------------------
     public static void timeOut() throws Throwable {
-        int count =0;
-        Basic test = new Basic();
+        int count = 0;
         CountDownLatch latch = new CountDownLatch(3);
         Awaiter[] a = new Awaiter[12];
 
@@ -162,54 +145,56 @@
 
         for (int i = 0; i < 3; i++) {
             CountDownLatch gate = new CountDownLatch(4);
-            AwaiterFactory factory1 = test.awaiterFactory(latch, gate);
-            AwaiterFactory factory2 = test.timedAwaiterFactory(latch, gate);
-            a[count] = test.awaiter(latch, gate, timeout[i]); a[count++].start();
-            a[count] = factory1.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
-            test.toTheStartingGate(gate);
-            System.out.println("Main Thread: " + latch.toString());
+            Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
+            a[count] = awaiter(latch, gate, timeout[i]); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            gate.await();
             latch.countDown();
             checkCount(latch, 2-i);
         }
-        for (int i = 0; i < 12; i++)
-            a[i].join();
-
-        for (int i = 0; i < 12; i++)
-            checkResult(a[i], null);
+        for (Awaiter awaiter : a)
+            awaiter.join();
+        for (Awaiter awaiter : a)
+            checkException(awaiter, null);
     }
 
     public static void main(String[] args) throws Throwable {
-        normalUse();
-        threadInterrupted();
-        timeOut();
+        try {
+            normalUse();
+        } catch (Throwable ex) { fail(ex); }
+        try {
+            threadInterrupted();
+        } catch (Throwable ex) { fail(ex); }
+        try {
+            timeOut();
+        } catch (Throwable ex) { fail(ex); }
+
         if (failures.get() > 0L)
             throw new AssertionError(failures.get() + " failures");
     }
 
-    private static final AtomicInteger failures = new AtomicInteger(0);
+    static final AtomicInteger failures = new AtomicInteger(0);
 
-    private static void fail(String msg) {
+    static void fail(String msg) {
         fail(new AssertionError(msg));
     }
 
-    private static void fail(Throwable t) {
+    static void fail(Throwable t) {
         t.printStackTrace();
         failures.getAndIncrement();
     }
 
-    private static void checkCount(CountDownLatch b, int expected) {
+    static void checkCount(CountDownLatch b, int expected) {
         if (b.getCount() != expected)
             fail("Count = " + b.getCount() +
                  ", expected = " + expected);
     }
 
-    private static void checkResult(Awaiter a, Class c) {
-        Throwable t = a.result();
-        if (! ((t == null && c == null) || c.isInstance(t))) {
-            System.out.println("Mismatch: " + t + ", " + c.getName());
-            failures.getAndIncrement();
-        }
+    static void checkException(Awaiter awaiter, Class<? extends Throwable> c) {
+        Throwable ex = awaiter.exception;
+        if (! ((ex == null && c == null) || c.isInstance(ex)))
+            fail("Expected: " + c + ", got: " + ex);
     }
 }
--- a/test/jdk/java/util/concurrent/CyclicBarrier/Basic.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/CyclicBarrier/Basic.java	Sun Sep 15 13:41:19 2019 +0200
@@ -37,6 +37,7 @@
 import java.util.concurrent.BrokenBarrierException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 import jdk.test.lib.Utils;
@@ -293,37 +294,42 @@
      * Handling of extra interrupts while waiting - tests for bug 6366811
      */
     private static void testInterrupts() {
-        final int N = 10;
+        final int N = ThreadLocalRandom.current().nextInt(2, 10);
         final CyclicBarrier startingGate = new CyclicBarrier(N+1);
 
         /**
          * A version of Awaiter that also records interrupted state.
          */
         class Waiter extends CheckedThread {
-            private boolean timed;
-            private CyclicBarrier barrier;
-            private CountDownLatch doneSignal;
-            private Throwable throwable;
-            private boolean interrupted;
+            private final boolean timed;
+            private final CyclicBarrier barrier;
+            private final CountDownLatch doneSignal;
+            volatile Throwable throwable;
+            volatile boolean interruptStatusSetAfterAwait;
 
-            public Waiter(boolean timed,
-                          CountDownLatch doneSignal,
-                          CyclicBarrier barrier) {
-                this.timed = timed;
+            public Waiter(CountDownLatch doneSignal, CyclicBarrier barrier) {
+                this.timed = ThreadLocalRandom.current().nextBoolean();
                 this.doneSignal = doneSignal;
                 this.barrier = barrier;
             }
-            Throwable throwable() { return this.throwable; }
-            boolean interruptBit() { return this.interrupted; }
+
             void realRun() throws Throwable {
                 startingGate.await(LONG_DELAY_MS, MILLISECONDS);
+
                 try {
                     if (timed) barrier.await(LONG_DELAY_MS, MILLISECONDS);
-                    else barrier.await(); }
-                catch (Throwable throwable) { this.throwable = throwable; }
+                    else barrier.await();
+                } catch (Throwable throwable) {
+                    this.throwable = throwable;
+                }
 
-                try { doneSignal.await(LONG_DELAY_MS, MILLISECONDS); }
-                catch (InterruptedException e) { interrupted = true; }
+                try {
+                    check(doneSignal.await(LONG_DELAY_MS, MILLISECONDS));
+                    if (Thread.interrupted())
+                        interruptStatusSetAfterAwait = true;
+                } catch (InterruptedException e) {
+                    interruptStatusSetAfterAwait = true;
+                }
             }
         }
 
@@ -352,7 +358,7 @@
                 } catch (Throwable t) { unexpected(t); }
             }};
             for (int i = 0; i < N; i++) {
-                Waiter waiter = new Waiter(i < N/2, doneSignal, barrier);
+                Waiter waiter = new Waiter(doneSignal, barrier);
                 waiter.start();
                 waiters.add(waiter);
             }
@@ -360,16 +366,14 @@
             while (barrier.getNumberWaiting() < N) Thread.yield();
             barrier.await();
             doneSignal.countDown();
-            int countInterrupted = 0;
-            int countInterruptedException = 0;
-            int countBrokenBarrierException = 0;
+            int countInterruptStatusSetAfterAwait = 0;
             for (Waiter waiter : waiters) {
                 waiter.join();
-                equal(waiter.throwable(), null);
-                if (waiter.interruptBit())
-                    countInterrupted++;
+                equal(waiter.throwable, null);
+                if (waiter.interruptStatusSetAfterAwait)
+                    countInterruptStatusSetAfterAwait++;
             }
-            equal(countInterrupted, N/2);
+            equal(countInterruptStatusSetAfterAwait, N/2);
             check(! barrier.isBroken());
         } catch (Throwable t) { unexpected(t); }
 
@@ -381,31 +385,33 @@
             final CyclicBarrier barrier = new CyclicBarrier(N+1);
             final List<Waiter> waiters = new ArrayList<>(N);
             for (int i = 0; i < N; i++) {
-                Waiter waiter = new Waiter(i < N/2, doneSignal, barrier);
+                Waiter waiter = new Waiter(doneSignal, barrier);
                 waiter.start();
                 waiters.add(waiter);
             }
             startingGate.await(LONG_DELAY_MS, MILLISECONDS);
             while (barrier.getNumberWaiting() < N) Thread.yield();
-            for (int i = 0; i < N/2; i++)
-                waiters.get(i).interrupt();
+            for (int i = 0; i < N/2; i++) {
+                Thread waiter = waiters.get(i);
+                waiter.interrupt();
+            }
             doneSignal.countDown();
-            int countInterrupted = 0;
             int countInterruptedException = 0;
             int countBrokenBarrierException = 0;
+            int countInterruptStatusSetAfterAwait = 0;
             for (Waiter waiter : waiters) {
                 waiter.join();
-                if (waiter.throwable() instanceof InterruptedException)
+                if (waiter.throwable instanceof InterruptedException)
                     countInterruptedException++;
-                if (waiter.throwable() instanceof BrokenBarrierException)
+                if (waiter.throwable instanceof BrokenBarrierException)
                     countBrokenBarrierException++;
-                if (waiter.interruptBit())
-                    countInterrupted++;
+                if (waiter.interruptStatusSetAfterAwait)
+                    countInterruptStatusSetAfterAwait++;
             }
-            equal(countInterrupted, N/2-1);
             equal(countInterruptedException, 1);
             equal(countBrokenBarrierException, N-1);
             checkBroken(barrier);
+            equal(countInterruptStatusSetAfterAwait, N/2-1);
             reset(barrier);
         } catch (Throwable t) { unexpected(t); }
     }
--- a/test/jdk/java/util/concurrent/FutureTask/BlockingTaskExecutor.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/FutureTask/BlockingTaskExecutor.java	Sun Sep 15 13:41:19 2019 +0200
@@ -103,7 +103,7 @@
      */
     static class NotificationReceiver {
         /** Has the notifiee been notified? */
-        boolean notified = false;
+        boolean notified;
 
         /**
          * Notify the notification receiver.
--- a/test/jdk/java/util/concurrent/FutureTask/CancelledFutureLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/FutureTask/CancelledFutureLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -130,7 +130,7 @@
             long endTime = System.nanoTime();
             long time = endTime - timer.startTime;
             if (print) {
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/FutureTask/DoneTimedGetLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/FutureTask/DoneTimedGetLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -33,6 +33,7 @@
 
 /*
  * @test
+ * @library /test/lib
  * @run main DoneTimedGetLoops 300
  * @summary isDone returning true guarantees that subsequent timed get
  * will never throw TimeoutException.
@@ -42,10 +43,12 @@
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
+import jdk.test.lib.Utils;
 
 @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
 public class DoneTimedGetLoops {
-    final long testDurationMillisDefault = 10L * 1000L;
+    static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
+    final long testDurationMillisDefault = 10_000L;
     final long testDurationMillis;
 
     static class PublicFutureTask extends FutureTask<Boolean> {
@@ -63,7 +66,6 @@
     void test(String[] args) throws Throwable {
         final long testDurationNanos = testDurationMillis * 1000L * 1000L;
         final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
-        final long timeoutMillis = 10L * 1000L;
 
         final AtomicReference<PublicFutureTask> normalRef
             = new AtomicReference<>();
@@ -136,13 +138,13 @@
                  setterException,
                  doneTimedGetNormal,
                  doneTimedGetAbnormal }) {
-            thread.join(timeoutMillis + testDurationMillis);
+            thread.join(LONG_DELAY_MS + testDurationMillis);
             if (thread.isAlive()) {
                 System.err.printf("Hung thread: %s%n", thread.getName());
                 failed++;
                 for (StackTraceElement e : thread.getStackTrace())
                     System.err.println(e);
-                thread.join(timeoutMillis);
+                thread.join(LONG_DELAY_MS);
             }
         }
     }
--- a/test/jdk/java/util/concurrent/Phaser/FickleRegister.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/Phaser/FickleRegister.java	Sun Sep 15 13:41:19 2019 +0200
@@ -43,7 +43,7 @@
 
 public class FickleRegister {
     final AtomicLong count = new AtomicLong(0);
-    final long testDurationMillisDefault = 10L * 1000L;
+    final long testDurationMillisDefault = 10_000L;
     final long testDurationMillis;
     final long quittingTimeNanos;
     final int chunkSize = 1000;
--- a/test/jdk/java/util/concurrent/Phaser/TieredArriveLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/Phaser/TieredArriveLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -40,7 +40,7 @@
 import java.util.concurrent.Phaser;
 
 public class TieredArriveLoops {
-    final long testDurationMillisDefault = 10L * 1000L;
+    final long testDurationMillisDefault = 10_000L;
     final long testDurationMillis;
     final long quittingTimeNanos;
 
--- a/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/GCRetention.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/GCRetention.java	Sun Sep 15 13:41:19 2019 +0200
@@ -86,7 +86,7 @@
                     if (q.remove(1000) != null)
                         break;
                     System.out.printf(
-                        "%d/%d unqueued references remaining%n", j, n);
+                        "%d/%d unqueued references remaining%n", j + 1, n);
                 }
             }
         }
--- a/test/jdk/java/util/concurrent/TimeUnit/Basic.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/TimeUnit/Basic.java	Sun Sep 15 13:41:19 2019 +0200
@@ -24,6 +24,7 @@
 /* @test
  * @bug 5057341 6363898
  * @summary Basic tests for TimeUnit
+ * @library /test/lib
  * @author Martin Buchholz
  */
 
@@ -39,12 +40,20 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 import java.io.ObjectOutputStream;
 import java.io.ObjectInputStream;
 import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import jdk.test.lib.Utils;
 
 public class Basic {
+    static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
+
     private static void realMain(String[] args) throws Throwable {
 
         for (TimeUnit u : TimeUnit.values()) {
@@ -71,18 +80,33 @@
         equal(1000L, MILLISECONDS.toMicros(1));
         equal(1000L, MICROSECONDS.toNanos(1));
 
-        long t0 = System.nanoTime();
-        MILLISECONDS.sleep(3); /* See windows bug 6313903, might not sleep */
-        long elapsedMillis = (System.nanoTime() - t0)/(1000L * 1000L);
-        System.out.printf("elapsed=%d%n", elapsedMillis);
-        check(elapsedMillis >= 0);
-        /* Might not sleep on windows: check(elapsedMillis >= 3); */
-        check(elapsedMillis < 1000);
+        //----------------------------------------------------------------
+        // TimeUnit.sleep sleeps for at least the specified time.
+        // TimeUnit.sleep(x, unit) for x <= 0 does not sleep at all.
+        //----------------------------------------------------------------
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        int maxTimeoutMillis = rnd.nextInt(1, 12);
+        List<CompletableFuture<?>> workers =
+            IntStream.range(-1, maxTimeoutMillis + 1)
+            .mapToObj(timeoutMillis -> (Runnable) () -> {
+                try {
+                    long startTime = System.nanoTime();
+                    MILLISECONDS.sleep(timeoutMillis);
+                    long elapsedNanos = System.nanoTime() - startTime;
+                    long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis);
+                    check(elapsedNanos >= timeoutNanos);
+                } catch (InterruptedException fail) {
+                    throw new AssertionError(fail);
+                }})
+            .map(CompletableFuture::runAsync)
+            .collect(Collectors.toList());
+
+        workers.forEach(CompletableFuture<?>::join);
 
         //----------------------------------------------------------------
         // Tests for serialized form compatibility with previous release
         //----------------------------------------------------------------
-        byte[] serializedForm = /* Generated using tiger */
+        byte[] serializedForm = /* Generated using JDK 5 */
             {-84, -19, 0, 5, '~', 'r', 0, 29, 'j', 'a', 'v', 'a', '.',
              'u', 't', 'i', 'l', '.', 'c', 'o', 'n', 'c', 'u', 'r', 'r', 'e',
              'n', 't', '.', 'T', 'i', 'm', 'e', 'U', 'n', 'i', 't', 0, 0,
--- a/test/jdk/java/util/concurrent/atomic/DoubleAdderDemo.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/atomic/DoubleAdderDemo.java	Sun Sep 15 13:41:19 2019 +0200
@@ -103,8 +103,8 @@
         long total = (long)nthreads * incs;
         if (sum != (double)total)
             throw new Error(sum + " != " + total);
-        double secs = (double)time / (1000L * 1000 * 1000);
-        long rate = total * (1000L) / time;
+        double secs = (double)time / 1000_000_000L;
+        long rate = total * 1000L / time;
         System.out.printf("threads:%3d  Time: %7.3fsec  Incs per microsec: %4d\n",
                           nthreads, secs, rate);
     }
--- a/test/jdk/java/util/concurrent/locks/Lock/CheckedLockLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/Lock/CheckedLockLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -136,7 +136,7 @@
             long time = timer.getTime();
             long tpi = time / (iters * nthreads);
             System.out.print("\t" + LoopHelpers.rightJustify(tpi) + " ns per update");
-            //                double secs = (double)(time) / 1000000000.0;
+            //                double secs = (double)time / 1000000000.0;
             //                System.out.print("\t " + secs + "s run time");
             System.out.println();
 
--- a/test/jdk/java/util/concurrent/locks/Lock/FlakyMutex.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/Lock/FlakyMutex.java	Sun Sep 15 13:41:19 2019 +0200
@@ -49,31 +49,51 @@
     static class MyRuntimeException extends RuntimeException {}
 
     static void checkThrowable(Throwable t) {
-        check((t instanceof MyError) ||
+        if (!((t instanceof MyError) ||
               (t instanceof MyException) ||
-              (t instanceof MyRuntimeException));
+              (t instanceof MyRuntimeException)))
+            unexpected(t);
     }
 
     static void realMain(String[] args) throws Throwable {
-        final int nThreads = 3;
+        final ThreadLocalRandom rndMain = ThreadLocalRandom.current();
+        final int nCpus = Runtime.getRuntime().availableProcessors();
+        final int maxThreads = Math.min(4, nCpus);
+        final int nThreads = rndMain.nextInt(1, maxThreads + 1);
         final int iterations = 10_000;
         final CyclicBarrier startingGate = new CyclicBarrier(nThreads);
+        final ExecutorService es = Executors.newFixedThreadPool(nThreads);
         final FlakyMutex mutex = new FlakyMutex();
-        final ExecutorService es = Executors.newFixedThreadPool(nThreads);
         final Runnable task = () -> {
             try {
+                ThreadLocalRandom rnd = ThreadLocalRandom.current();
                 startingGate.await();
                 for (int i = 0; i < iterations; i++) {
                     for (;;) {
-                        try { mutex.lock(); break; }
-                        catch (Throwable t) { checkThrowable(t); }
+                        try {
+                            if (rnd.nextBoolean())
+                                mutex.lock();
+                            else
+                                mutex.lockInterruptibly();
+                            break;
+                        } catch (Throwable t) { checkThrowable(t); }
                     }
 
-                    try { check(! mutex.tryLock()); }
-                    catch (Throwable t) { checkThrowable(t); }
+                    if (rnd.nextBoolean()) {
+                        try {
+                            check(! mutex.tryLock());
+                        } catch (Throwable t) { checkThrowable(t); }
+                    }
 
-                    try { check(! mutex.tryLock(1, TimeUnit.MICROSECONDS)); }
-                    catch (Throwable t) { checkThrowable(t); }
+                    if (rnd.nextInt(10) == 0) {
+                        try {
+                            check(! mutex.tryLock(1, TimeUnit.MICROSECONDS));
+                        } catch (Throwable t) { checkThrowable(t); }
+                    }
+
+                    if (rnd.nextBoolean()) {
+                        check(mutex.isLocked());
+                    }
 
                     mutex.unlock();
                 }
@@ -146,7 +166,11 @@
         if (x == null ? y == null : x.equals(y)) pass();
         else fail(x + " not equal to " + y);}
     public static void main(String[] args) throws Throwable {
-        try {realMain(args);} catch (Throwable t) {unexpected(t);}
+        int runsPerTest = Integer.getInteger("jsr166.runsPerTest", 1);
+        try {
+            for (int i = runsPerTest; i--> 0; )
+                realMain(args);
+        } catch (Throwable t) { unexpected(t); }
         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
         if (failed > 0) throw new AssertionError("Some tests failed");}
     @SuppressWarnings("unchecked")
--- a/test/jdk/java/util/concurrent/locks/Lock/TimedAcquireLeak.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/Lock/TimedAcquireLeak.java	Sun Sep 15 13:41:19 2019 +0200
@@ -42,6 +42,8 @@
 import java.io.Reader;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
@@ -72,9 +74,9 @@
         return new File(bin, programName).getPath();
     }
 
-    static final String java = javaProgramPath("java");
-    static final String jmap = javaProgramPath("jmap");
-    static final String jps  = javaProgramPath("jps");
+    static final String javaPath = javaProgramPath("java");
+    static final String jmapPath = javaProgramPath("jmap");
+    static final String jpsPath  = javaProgramPath("jps");
 
     static String outputOf(Reader r) throws IOException {
         final StringBuilder sb = new StringBuilder();
@@ -159,7 +161,11 @@
 
     static String match(String s, String regex, int group) {
         Matcher matcher = Pattern.compile(regex).matcher(s);
-        matcher.find();
+        if (! matcher.find()) {
+            String msg = String.format(
+                "match failed: s=%s regex=%s", s, regex);
+            throw new AssertionError(msg);
+        }
         return matcher.group(group);
     }
 
@@ -171,21 +177,20 @@
 
     static int objectsInUse(final Process child,
                             final String childPid,
-                            final String className) {
-        final String regex =
-            "(?m)^ *[0-9]+: +([0-9]+) +[0-9]+ +\\Q"+className+"\\E(?:$| )";
-        final Callable<Integer> objectsInUse =
-            new Callable<Integer>() { public Integer call() {
-                Integer i = Integer.parseInt(
-                    match(commandOutputOf(jmap, "-histo:live", childPid),
-                          regex, 1));
-                if (i > 100)
-                    System.out.print(
-                        commandOutputOf(jmap,
-                                        "-dump:file=dump,format=b",
-                                        childPid));
-                return i;
-            }};
+                            final String classNameRegex) {
+        String regex =
+            "(?m)^ *[0-9]+: +([0-9]+) +[0-9]+ +"+classNameRegex+"(?:$| )";
+        Callable<Integer> objectsInUse = () -> {
+            int i = Integer.parseInt(
+                match(commandOutputOf(jmapPath, "-histo:live", childPid),
+                      regex, 1));
+            if (i > 100)
+                System.out.print(
+                    commandOutputOf(jmapPath,
+                                    "-dump:file=dump,format=b",
+                                    childPid));
+            return i;
+        };
         try { return rendezvousParent(child, objectsInUse); }
         catch (Throwable t) { unexpected(t); return -1; }
     }
@@ -196,26 +201,27 @@
             return;
 
         final String childClassName = Job.class.getName();
-        final String classToCheckForLeaks = Job.classToCheckForLeaks();
-        final String uniqueID =
-            String.valueOf(ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE));
+        final String classNameRegex = Job.classNameRegexToCheckForLeaks();
+        final String uniqueID = String.valueOf(
+            ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE));
 
-        final String[] jobCmd = {
-            java, "-Xmx8m", "-XX:+UsePerfData",
-            "-classpath", System.getProperty("test.class.path"),
-            childClassName, uniqueID
-        };
+        final ArrayList<String> jobCmd = new ArrayList<>();
+        Collections.addAll(
+            jobCmd, javaPath, "-Xmx8m", "-XX:+UsePerfData",
+            "-classpath", System.getProperty("test.class.path"));
+        Collections.addAll(jobCmd, Utils.getTestJavaOpts());
+        Collections.addAll(jobCmd, childClassName, uniqueID);
         final Process p = new ProcessBuilder(jobCmd).start();
         // Ensure subprocess jvm has started, so that jps can find it
         p.getInputStream().read();
         sendByte(p.getOutputStream());
 
         final String childPid =
-            match(commandOutputOf(jps, "-m"),
+            match(commandOutputOf(jpsPath, "-m"),
                   "(?m)^ *([0-9]+) +\\Q"+childClassName+"\\E *"+uniqueID+"$", 1);
 
-        final int n0 = objectsInUse(p, childPid, classToCheckForLeaks);
-        final int n1 = objectsInUse(p, childPid, classToCheckForLeaks);
+        final int n0 = objectsInUse(p, childPid, classNameRegex);
+        final int n1 = objectsInUse(p, childPid, classNameRegex);
         equal(p.waitFor(), 0);
         equal(p.exitValue(), 0);
         failed += p.exitValue();
@@ -226,7 +232,7 @@
         // implementation, and needing occasional adjustment.
         System.out.printf("%d -> %d%n", n0, n1);
         // Almost always n0 == n1
-        // Maximum jitter observed in practice is 10 -> 17
+        // Maximum jitter observed in practice is 7
         check(Math.abs(n1 - n0) < 10);
         check(n1 < 25);
         drainers.shutdown();
@@ -244,9 +250,9 @@
     // - in between calls to rendezvousChild, run code that may leak.
     //----------------------------------------------------------------
     public static class Job {
-        static String classToCheckForLeaks() {
+        static String classNameRegexToCheckForLeaks() {
             return
-                "java.util.concurrent.locks.AbstractQueuedSynchronizer$Node";
+                "\\Qjava.util.concurrent.locks.AbstractQueuedSynchronizer$\\E[A-Za-z]+";
         }
 
         public static void main(String[] args) throws Throwable {
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -93,7 +93,7 @@
             barrier.await();
             if (print) {
                 long time = timer.getTime();
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/LockOncePerThreadLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/LockOncePerThreadLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -94,7 +94,7 @@
             barrier.await();
             if (print) {
                 long time = timer.getTime();
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/SimpleReentrantLockLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/SimpleReentrantLockLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -95,7 +95,7 @@
                 long time = timer.getTime();
                 long tpi = time / ((long)iters * nthreads);
                 System.out.print("\t" + LoopHelpers.rightJustify(tpi) + " ns per lock");
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/TimeoutLockLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/TimeoutLockLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -96,7 +96,7 @@
             barrier.await();
             if (print) {
                 long time = timer.getTime();
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantReadWriteLock/MapLoops.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantReadWriteLock/MapLoops.java	Sun Sep 15 13:41:19 2019 +0200
@@ -91,8 +91,8 @@
             premove = Integer.parseInt(args[4]);
 
         // normalize probabilities wrt random number generator
-        removesPerMaxRandom = (int)(((double)premove/100.0 * 0x7FFFFFFFL));
-        insertsPerMaxRandom = (int)(((double)pinsert/100.0 * 0x7FFFFFFFL));
+        removesPerMaxRandom = (int)((double)premove/100.0 * 0x7FFFFFFFL);
+        insertsPerMaxRandom = (int)((double)pinsert/100.0 * 0x7FFFFFFFL);
 
         System.out.println("Using " + mapClass.getName());
 
@@ -125,7 +125,7 @@
             long time = timer.getTime();
             long tpo = time / (i * (long)nops);
             System.out.print(LoopHelpers.rightJustify(tpo) + " ns per op");
-            double secs = (double)(time) / 1000000000.0;
+            double secs = (double)time / 1000000000.0;
             System.out.println("\t " + secs + "s run time");
             map.clear();
         }
--- a/test/jdk/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -39,7 +39,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
 import java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject;
 
@@ -1286,19 +1286,31 @@
     /**
      * Tests scenario for
      * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw
+     * ant -Djsr166.tckTestClass=AbstractQueuedLongSynchronizerTest -Djsr166.methodFilter=testInterruptedFailingAcquire -Djsr166.runsPerTest=10000 tck
      */
-    public void testInterruptedFailingAcquire() throws InterruptedException {
-        final RuntimeException ex = new RuntimeException();
+    public void testInterruptedFailingAcquire() throws Throwable {
+        class PleaseThrow extends RuntimeException {}
+        final PleaseThrow ex = new PleaseThrow();
+        final AtomicBoolean thrown = new AtomicBoolean();
 
         // A synchronizer only offering a choice of failure modes
         class Sync extends AbstractQueuedLongSynchronizer {
-            boolean pleaseThrow;
+            volatile boolean pleaseThrow;
+            void maybeThrow() {
+                if (pleaseThrow) {
+                    // assert: tryAcquire methods can throw at most once
+                    if (! thrown.compareAndSet(false, true))
+                        throw new AssertionError();
+                    throw ex;
+                }
+            }
+
             @Override protected boolean tryAcquire(long ignored) {
-                if (pleaseThrow) throw ex;
+                maybeThrow();
                 return false;
             }
             @Override protected long tryAcquireShared(long ignored) {
-                if (pleaseThrow) throw ex;
+                maybeThrow();
                 return -1;
             }
             @Override protected boolean tryRelease(long ignored) {
@@ -1310,30 +1322,87 @@
         }
 
         final Sync s = new Sync();
+        final boolean acquireInterruptibly = randomBoolean();
+        final Action[] uninterruptibleAcquireActions = {
+            () -> s.acquire(1),
+            () -> s.acquireShared(1),
+        };
+        final long nanosTimeout = MILLISECONDS.toNanos(2 * LONG_DELAY_MS);
+        final Action[] interruptibleAcquireActions = {
+            () -> s.acquireInterruptibly(1),
+            () -> s.acquireSharedInterruptibly(1),
+            () -> s.tryAcquireNanos(1, nanosTimeout),
+            () -> s.tryAcquireSharedNanos(1, nanosTimeout),
+        };
+        final Action[] releaseActions = {
+            () -> s.release(1),
+            () -> s.releaseShared(1),
+        };
+        final Action acquireAction = acquireInterruptibly
+            ? chooseRandomly(interruptibleAcquireActions)
+            : chooseRandomly(uninterruptibleAcquireActions);
+        final Action releaseAction
+            = chooseRandomly(releaseActions);
 
+        // From os_posix.cpp:
+        //
+        // NOTE that since there is no "lock" around the interrupt and
+        // is_interrupted operations, there is the possibility that the
+        // interrupted flag (in osThread) will be "false" but that the
+        // low-level events will be in the signaled state. This is
+        // intentional. The effect of this is that Object.wait() and
+        // LockSupport.park() will appear to have a spurious wakeup, which
+        // is allowed and not harmful, and the possibility is so rare that
+        // it is not worth the added complexity to add yet another lock.
         final Thread thread = newStartedThread(new CheckedRunnable() {
-            public void realRun() {
+            public void realRun() throws Throwable {
                 try {
-                    if (ThreadLocalRandom.current().nextBoolean())
-                        s.acquire(1);
-                    else
-                        s.acquireShared(1);
+                    acquireAction.run();
                     shouldThrow();
-                } catch (Throwable t) {
-                    assertSame(ex, t);
-                    assertTrue(Thread.interrupted());
+                } catch (InterruptedException possible) {
+                    assertTrue(acquireInterruptibly);
+                    assertFalse(Thread.interrupted());
+                } catch (PleaseThrow possible) {
+                    awaitInterrupted();
                 }
             }});
-        waitForThreadToEnterWaitState(thread);
-        assertSame(thread, s.getFirstQueuedThread());
-        assertTrue(s.hasQueuedPredecessors());
-        assertTrue(s.hasQueuedThreads());
-        assertEquals(1, s.getQueueLength());
+        for (long startTime = 0L;; ) {
+            waitForThreadToEnterWaitState(thread);
+            if (s.getFirstQueuedThread() == thread
+                && s.hasQueuedPredecessors()
+                && s.hasQueuedThreads()
+                && s.getQueueLength() == 1
+                && s.hasContended())
+                break;
+            if (startTime == 0L)
+                startTime = System.nanoTime();
+            else if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+                fail("timed out waiting for AQS state: "
+                     + "thread state=" + thread.getState()
+                     + ", queued threads=" + s.getQueuedThreads());
+            Thread.yield();
+        }
 
         s.pleaseThrow = true;
-        thread.interrupt();
-        s.release(1);
+        // release and interrupt, in random order
+        if (randomBoolean()) {
+            thread.interrupt();
+            releaseAction.run();
+        } else {
+            releaseAction.run();
+            thread.interrupt();
+        }
         awaitTermination(thread);
+
+        if (! acquireInterruptibly)
+            assertTrue(thrown.get());
+
+        assertNull(s.getFirstQueuedThread());
+        assertFalse(s.hasQueuedPredecessors());
+        assertFalse(s.hasQueuedThreads());
+        assertEquals(0, s.getQueueLength());
+        assertTrue(s.getQueuedThreads().isEmpty());
+        assertTrue(s.hasContended());
     }
 
 }
--- a/test/jdk/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -40,7 +40,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.locks.AbstractQueuedSynchronizer;
 import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject;
 
@@ -1337,19 +1337,31 @@
     /**
      * Tests scenario for
      * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw
+     * ant -Djsr166.tckTestClass=AbstractQueuedSynchronizerTest -Djsr166.methodFilter=testInterruptedFailingAcquire -Djsr166.runsPerTest=10000 tck
      */
-    public void testInterruptedFailingAcquire() throws InterruptedException {
-        final RuntimeException ex = new RuntimeException();
+    public void testInterruptedFailingAcquire() throws Throwable {
+        class PleaseThrow extends RuntimeException {}
+        final PleaseThrow ex = new PleaseThrow();
+        final AtomicBoolean thrown = new AtomicBoolean();
 
         // A synchronizer only offering a choice of failure modes
         class Sync extends AbstractQueuedSynchronizer {
-            boolean pleaseThrow;
+            volatile boolean pleaseThrow;
+            void maybeThrow() {
+                if (pleaseThrow) {
+                    // assert: tryAcquire methods can throw at most once
+                    if (! thrown.compareAndSet(false, true))
+                        throw new AssertionError();
+                    throw ex;
+                }
+            }
+
             @Override protected boolean tryAcquire(int ignored) {
-                if (pleaseThrow) throw ex;
+                maybeThrow();
                 return false;
             }
             @Override protected int tryAcquireShared(int ignored) {
-                if (pleaseThrow) throw ex;
+                maybeThrow();
                 return -1;
             }
             @Override protected boolean tryRelease(int ignored) {
@@ -1361,30 +1373,87 @@
         }
 
         final Sync s = new Sync();
+        final boolean acquireInterruptibly = randomBoolean();
+        final Action[] uninterruptibleAcquireActions = {
+            () -> s.acquire(1),
+            () -> s.acquireShared(1),
+        };
+        final long nanosTimeout = MILLISECONDS.toNanos(2 * LONG_DELAY_MS);
+        final Action[] interruptibleAcquireActions = {
+            () -> s.acquireInterruptibly(1),
+            () -> s.acquireSharedInterruptibly(1),
+            () -> s.tryAcquireNanos(1, nanosTimeout),
+            () -> s.tryAcquireSharedNanos(1, nanosTimeout),
+        };
+        final Action[] releaseActions = {
+            () -> s.release(1),
+            () -> s.releaseShared(1),
+        };
+        final Action acquireAction = acquireInterruptibly
+            ? chooseRandomly(interruptibleAcquireActions)
+            : chooseRandomly(uninterruptibleAcquireActions);
+        final Action releaseAction
+            = chooseRandomly(releaseActions);
 
+        // From os_posix.cpp:
+        //
+        // NOTE that since there is no "lock" around the interrupt and
+        // is_interrupted operations, there is the possibility that the
+        // interrupted flag (in osThread) will be "false" but that the
+        // low-level events will be in the signaled state. This is
+        // intentional. The effect of this is that Object.wait() and
+        // LockSupport.park() will appear to have a spurious wakeup, which
+        // is allowed and not harmful, and the possibility is so rare that
+        // it is not worth the added complexity to add yet another lock.
         final Thread thread = newStartedThread(new CheckedRunnable() {
-            public void realRun() {
+            public void realRun() throws Throwable {
                 try {
-                    if (ThreadLocalRandom.current().nextBoolean())
-                        s.acquire(1);
-                    else
-                        s.acquireShared(1);
+                    acquireAction.run();
                     shouldThrow();
-                } catch (Throwable t) {
-                    assertSame(ex, t);
-                    assertTrue(Thread.interrupted());
+                } catch (InterruptedException possible) {
+                    assertTrue(acquireInterruptibly);
+                    assertFalse(Thread.interrupted());
+                } catch (PleaseThrow possible) {
+                    awaitInterrupted();
                 }
             }});
-        waitForThreadToEnterWaitState(thread);
-        assertSame(thread, s.getFirstQueuedThread());
-        assertTrue(s.hasQueuedPredecessors());
-        assertTrue(s.hasQueuedThreads());
-        assertEquals(1, s.getQueueLength());
+        for (long startTime = 0L;; ) {
+            waitForThreadToEnterWaitState(thread);
+            if (s.getFirstQueuedThread() == thread
+                && s.hasQueuedPredecessors()
+                && s.hasQueuedThreads()
+                && s.getQueueLength() == 1
+                && s.hasContended())
+                break;
+            if (startTime == 0L)
+                startTime = System.nanoTime();
+            else if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+                fail("timed out waiting for AQS state: "
+                     + "thread state=" + thread.getState()
+                     + ", queued threads=" + s.getQueuedThreads());
+            Thread.yield();
+        }
 
         s.pleaseThrow = true;
-        thread.interrupt();
-        s.release(1);
+        // release and interrupt, in random order
+        if (randomBoolean()) {
+            thread.interrupt();
+            releaseAction.run();
+        } else {
+            releaseAction.run();
+            thread.interrupt();
+        }
         awaitTermination(thread);
+
+        if (! acquireInterruptibly)
+            assertTrue(thrown.get());
+
+        assertNull(s.getFirstQueuedThread());
+        assertFalse(s.hasQueuedPredecessors());
+        assertFalse(s.hasQueuedThreads());
+        assertEquals(0, s.getQueueLength());
+        assertTrue(s.getQueuedThreads().isEmpty());
+        assertTrue(s.hasContended());
     }
 
 }
--- a/test/jdk/java/util/concurrent/tck/ArrayBlockingQueueTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ArrayBlockingQueueTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -61,7 +61,7 @@
         class Implementation implements CollectionImplementation {
             public Class<?> klazz() { return ArrayBlockingQueue.class; }
             public Collection emptyCollection() {
-                boolean fair = ThreadLocalRandom.current().nextBoolean();
+                boolean fair = randomBoolean();
                 return populatedQueue(0, SIZE, 2 * SIZE, fair);
             }
             public Object makeElement(int i) { return i; }
@@ -367,7 +367,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(SIZE, q.size());
@@ -409,7 +409,7 @@
         assertEquals(0, q.take());
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -431,21 +431,21 @@
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -486,7 +486,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -539,29 +539,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
--- a/test/jdk/java/util/concurrent/tck/BlockingQueueTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/BlockingQueueTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -253,7 +253,7 @@
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
@@ -274,7 +274,7 @@
         assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
 
         barrier.await();
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -296,7 +296,7 @@
             }});
 
         await(threadStarted);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -325,19 +325,19 @@
      */
     public void testTimedPollFromEmptyBlocksInterruptibly() {
         final BlockingQueue q = emptyCollection();
-        final CountDownLatch threadStarted = new CountDownLatch(1);
+        final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() {
-                threadStarted.countDown();
+                pleaseInterrupt.countDown();
                 try {
-                    q.poll(2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
-        await(threadStarted);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        await(pleaseInterrupt);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -352,7 +352,7 @@
             public void realRun() {
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
--- a/test/jdk/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -940,7 +940,7 @@
     }
 
     void runAsync(Runnable r1, Runnable r2) {
-        boolean b = ThreadLocalRandom.current().nextBoolean();
+        boolean b = randomBoolean();
         CompletableFuture<Void> f1 = CompletableFuture.runAsync(b ? r1 : r2);
         CompletableFuture<Void> f2 = CompletableFuture.runAsync(b ? r2 : r1);
         f1.join();
@@ -1003,10 +1003,6 @@
         }
     }
 
-    <T> T chooseRandomly(T... choices) {
-        return choices[ThreadLocalRandom.current().nextInt(choices.length)];
-    }
-
     /**
      * Non-traversing Deque operations (that return null) are linearizable.
      * Don't return null when the deque is observably never empty.
--- a/test/jdk/java/util/concurrent/tck/CountDownLatchTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/CountDownLatchTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -36,6 +36,7 @@
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -99,7 +100,7 @@
         assertEquals(2, l.getCount());
         l.countDown();
         assertEquals(1, l.getCount());
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         l.countDown();
         assertEquals(0, l.getCount());
         awaitTermination(t);
@@ -124,7 +125,7 @@
         assertEquals(2, l.getCount());
         l.countDown();
         assertEquals(1, l.getCount());
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         l.countDown();
         assertEquals(0, l.getCount());
         awaitTermination(t);
@@ -156,7 +157,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -165,29 +166,30 @@
      * timed await throws InterruptedException if interrupted before counted down
      */
     public void testTimedAwait_Interruptible() {
-        final CountDownLatch l = new CountDownLatch(1);
+        final int initialCount = ThreadLocalRandom.current().nextInt(1, 3);
+        final CountDownLatch l = new CountDownLatch(initialCount);
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
                 Thread.currentThread().interrupt();
                 try {
-                    l.await(LONG_DELAY_MS, MILLISECONDS);
+                    l.await(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    l.await(LONG_DELAY_MS, MILLISECONDS);
+                    l.await(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
-                assertEquals(1, l.getCount());
+                assertEquals(initialCount, l.getCount());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -200,7 +202,11 @@
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
                 assertEquals(1, l.getCount());
+
+                long startTime = System.nanoTime();
                 assertFalse(l.await(timeoutMillis(), MILLISECONDS));
+                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+
                 assertEquals(1, l.getCount());
             }});
 
--- a/test/jdk/java/util/concurrent/tck/CyclicBarrierTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/CyclicBarrierTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -42,7 +42,6 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import junit.framework.Test;
@@ -323,34 +322,6 @@
     }
 
     /**
-     * All threads block while a barrier is broken.
-     */
-    public void testReset_Leakage() throws InterruptedException {
-        final CyclicBarrier c = new CyclicBarrier(2);
-        final AtomicBoolean done = new AtomicBoolean();
-        Thread t = newStartedThread(new CheckedRunnable() {
-            public void realRun() {
-                while (!done.get()) {
-                    try {
-                        while (c.isBroken())
-                            c.reset();
-
-                        c.await();
-                        shouldThrow();
-                    }
-                    catch (BrokenBarrierException | InterruptedException ok) {}
-                }}});
-
-        for (int i = 0; i < 4; i++) {
-            delay(timeoutMillis());
-            t.interrupt();
-        }
-        done.set(true);
-        t.interrupt();
-        awaitTermination(t);
-    }
-
-    /**
      * Reset of a non-broken barrier does not break barrier
      */
     public void testResetWithoutBreakage() throws Exception {
@@ -505,7 +476,7 @@
         final ExecutorService e = Executors.newFixedThreadPool(nTasks);
         final Runnable awaiter = () -> {
             try {
-                if (ThreadLocalRandom.current().nextBoolean())
+                if (randomBoolean())
                     barrier.await();
                 else
                     barrier.await(LONG_DELAY_MS, MILLISECONDS);
--- a/test/jdk/java/util/concurrent/tck/DelayQueueTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/DelayQueueTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -332,7 +332,7 @@
     }
 
     /**
-     * timed offer does not time out
+     * Queue is unbounded, so timed offer never times out
      */
     public void testTimedOffer() throws InterruptedException {
         final DelayQueue q = new DelayQueue();
@@ -384,7 +384,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -436,30 +436,27 @@
         final DelayQueue q = populatedQueue(SIZE);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(new PDelay(i),
                                  ((PDelay)q.poll(LONG_DELAY_MS, MILLISECONDS)));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
--- a/test/jdk/java/util/concurrent/tck/DoubleAccumulatorTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/DoubleAccumulatorTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -156,7 +156,7 @@
             = new DoubleAccumulator((x, y) -> x + y, 0.0);
         final int nThreads = ThreadLocalRandom.current().nextInt(1, 5);
         final Phaser phaser = new Phaser(nThreads + 1);
-        final int incs = 1_000_000;
+        final int incs = expensiveTests ? 1_000_000 : 100_000;
         final double total = nThreads * incs/2.0 * (incs - 1); // Gauss
         final Runnable task = () -> {
             phaser.arriveAndAwaitAdvance();
--- a/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java	Sun Sep 15 13:41:19 2019 +0200
@@ -38,7 +38,6 @@
 import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.ForkJoinTask;
 import java.util.concurrent.Future;
-import java.util.concurrent.ThreadLocalRandom;
 import java.util.stream.Stream;
 
 import junit.framework.Test;
@@ -81,7 +80,7 @@
             Thread currentThread = Thread.currentThread();
 
             Stream.of(systemClassLoader, null).forEach(cl -> {
-                if (ThreadLocalRandom.current().nextBoolean())
+                if (randomBoolean())
                     // should always be permitted, without effect
                     currentThread.setContextClassLoader(cl);
                 });
--- a/test/jdk/java/util/concurrent/tck/ForkJoinTask8Test.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ForkJoinTask8Test.java	Sun Sep 15 13:41:19 2019 +0200
@@ -559,6 +559,8 @@
                 AsyncFib f = new AsyncFib(8);
                 assertSame(f, f.fork());
                 helpQuiesce();
+                while (!f.isDone()) // wait out race
+                    ;
                 assertEquals(0, getQueuedTaskCount());
                 f.checkCompletedNormally();
             }};
--- a/test/jdk/java/util/concurrent/tck/ForkJoinTaskTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ForkJoinTaskTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -526,6 +526,8 @@
                 AsyncFib f = new AsyncFib(8);
                 assertSame(f, f.fork());
                 helpQuiesce();
+                while (!f.isDone()) // wait out race
+                    ;
                 assertEquals(21, f.number);
                 assertEquals(0, getQueuedTaskCount());
                 checkCompletedNormally(f);
--- a/test/jdk/java/util/concurrent/tck/FutureTaskTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/FutureTaskTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -747,7 +747,7 @@
     /**
      * get is interruptible
      */
-    public void testGet_interruptible() {
+    public void testGet_Interruptible() {
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         final FutureTask task = new FutureTask(new NoOpCallable());
         Thread t = newStartedThread(new CheckedRunnable() {
@@ -776,27 +776,28 @@
     /**
      * timed get is interruptible
      */
-    public void testTimedGet_interruptible() {
+    public void testTimedGet_Interruptible() {
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         final FutureTask task = new FutureTask(new NoOpCallable());
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws Exception {
                 Thread.currentThread().interrupt();
                 try {
-                    task.get(2*LONG_DELAY_MS, MILLISECONDS);
+                    task.get(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    task.get(2*LONG_DELAY_MS, MILLISECONDS);
+                    task.get(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkNotDone(task);
--- a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java	Sun Sep 15 13:41:19 2019 +0200
@@ -311,12 +311,13 @@
     static volatile TestCase currentTestCase;
     // static volatile int currentRun = 0;
     static {
-        Runnable checkForWedgedTest = new Runnable() { public void run() {
+        Runnable wedgedTestDetector = new Runnable() { public void run() {
             // Avoid spurious reports with enormous runsPerTest.
             // A single test case run should never take more than 1 second.
             // But let's cap it at the high end too ...
-            final int timeoutMinutes =
-                Math.min(15, Math.max(runsPerTest / 60, 1));
+            final int timeoutMinutesMin = Math.max(runsPerTest / 60, 1)
+                * Math.max((int) delayFactor, 1);
+            final int timeoutMinutes = Math.min(15, timeoutMinutesMin);
             for (TestCase lastTestCase = currentTestCase;;) {
                 try { MINUTES.sleep(timeoutMinutes); }
                 catch (InterruptedException unexpected) { break; }
@@ -336,7 +337,7 @@
                 }
                 lastTestCase = currentTestCase;
             }}};
-        Thread thread = new Thread(checkForWedgedTest, "checkForWedgedTest");
+        Thread thread = new Thread(wedgedTestDetector, "WedgedTestDetector");
         thread.setDaemon(true);
         thread.start();
     }
@@ -380,7 +381,7 @@
             // Never report first run of any test; treat it as a
             // warmup run, notably to trigger all needed classloading,
             if (i > 0)
-                System.out.printf("%n%s: %d%n", toString(), elapsedMillis);
+                System.out.printf("%s: %d%n", toString(), elapsedMillis);
         }
     }
 
@@ -683,6 +684,12 @@
     public static long MEDIUM_DELAY_MS;
     public static long LONG_DELAY_MS;
 
+    /**
+     * A delay significantly longer than LONG_DELAY_MS.
+     * Use this in a thread that is waited for via awaitTermination(Thread).
+     */
+    public static long LONGER_DELAY_MS;
+
     private static final long RANDOM_TIMEOUT;
     private static final long RANDOM_EXPIRED_TIMEOUT;
     private static final TimeUnit RANDOM_TIMEUNIT;
@@ -711,6 +718,20 @@
     static TimeUnit randomTimeUnit() { return RANDOM_TIMEUNIT; }
 
     /**
+     * Returns a random boolean; a "coin flip".
+     */
+    static boolean randomBoolean() {
+        return ThreadLocalRandom.current().nextBoolean();
+    }
+
+    /**
+     * Returns a random element from given choices.
+     */
+    <T> T chooseRandomly(T... choices) {
+        return choices[ThreadLocalRandom.current().nextInt(choices.length)];
+    }
+
+    /**
      * Returns the shortest timed delay. This can be scaled up for
      * slow machines using the jsr166.delay.factor system property,
      * or via jtreg's -timeoutFactor: flag.
@@ -728,6 +749,7 @@
         SMALL_DELAY_MS  = SHORT_DELAY_MS * 5;
         MEDIUM_DELAY_MS = SHORT_DELAY_MS * 10;
         LONG_DELAY_MS   = SHORT_DELAY_MS * 200;
+        LONGER_DELAY_MS = 2 * LONG_DELAY_MS;
     }
 
     private static final long TIMEOUT_DELAY_MS
@@ -766,8 +788,8 @@
      */
     public void threadRecordFailure(Throwable t) {
         System.err.println(t);
-        dumpTestThreads();
-        threadFailure.compareAndSet(null, t);
+        if (threadFailure.compareAndSet(null, t))
+            dumpTestThreads();
     }
 
     public void setUp() {
@@ -1088,6 +1110,39 @@
         }
     }
 
+    /** Returns true if thread info might be useful in a thread dump. */
+    static boolean threadOfInterest(ThreadInfo info) {
+        final String name = info.getThreadName();
+        String lockName;
+        if (name == null)
+            return true;
+        if (name.equals("Signal Dispatcher")
+            || name.equals("WedgedTestDetector"))
+            return false;
+        if (name.equals("Reference Handler")) {
+            // Reference Handler stacktrace changed in JDK-8156500
+            StackTraceElement[] stackTrace; String methodName;
+            if ((stackTrace = info.getStackTrace()) != null
+                && stackTrace.length > 0
+                && (methodName = stackTrace[0].getMethodName()) != null
+                && methodName.equals("waitForReferencePendingList"))
+                return false;
+            // jdk8 Reference Handler stacktrace
+            if ((lockName = info.getLockName()) != null
+                && lockName.startsWith("java.lang.ref"))
+                return false;
+        }
+        if ((name.equals("Finalizer") || name.equals("Common-Cleaner"))
+            && (lockName = info.getLockName()) != null
+            && lockName.startsWith("java.lang.ref"))
+            return false;
+        if (name.startsWith("ForkJoinPool.commonPool-worker")
+            && (lockName = info.getLockName()) != null
+            && lockName.startsWith("java.util.concurrent.ForkJoinPool"))
+            return false;
+        return true;
+    }
+
     /**
      * A debugging tool to print stack traces of most threads, as jstack does.
      * Uninteresting threads are filtered out.
@@ -1104,23 +1159,9 @@
 
         ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
         System.err.println("------ stacktrace dump start ------");
-        for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
-            final String name = info.getThreadName();
-            String lockName;
-            if ("Signal Dispatcher".equals(name))
-                continue;
-            if ("Reference Handler".equals(name)
-                && (lockName = info.getLockName()) != null
-                && lockName.startsWith("java.lang.ref.Reference$Lock"))
-                continue;
-            if ("Finalizer".equals(name)
-                && (lockName = info.getLockName()) != null
-                && lockName.startsWith("java.lang.ref.ReferenceQueue$Lock"))
-                continue;
-            if ("checkForWedgedTest".equals(name))
-                continue;
-            System.err.print(info);
-        }
+        for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true))
+            if (threadOfInterest(info))
+                System.err.print(info);
         System.err.println("------ stacktrace dump end ------");
 
         if (sm != null) System.setSecurityManager(sm);
@@ -1393,6 +1434,20 @@
     }
 
     /**
+     * Spin-waits up to LONG_DELAY_MS milliseconds for the current thread to
+     * be interrupted.  Clears the interrupt status before returning.
+     */
+    void awaitInterrupted() {
+        for (long startTime = 0L; !Thread.interrupted(); ) {
+            if (startTime == 0L)
+                startTime = System.nanoTime();
+            else if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+                fail("timed out waiting for thread interrupt");
+            Thread.yield();
+        }
+    }
+
+    /**
      * Returns the number of milliseconds since time given by
      * startNanoTime, which must have been previously returned from a
      * call to {@link System#nanoTime()}.
@@ -1401,19 +1456,6 @@
         return NANOSECONDS.toMillis(System.nanoTime() - startNanoTime);
     }
 
-//     void assertTerminatesPromptly(long timeoutMillis, Runnable r) {
-//         long startTime = System.nanoTime();
-//         try {
-//             r.run();
-//         } catch (Throwable fail) { threadUnexpectedException(fail); }
-//         if (millisElapsedSince(startTime) > timeoutMillis/2)
-//             throw new AssertionError("did not return promptly");
-//     }
-
-//     void assertTerminatesPromptly(Runnable r) {
-//         assertTerminatesPromptly(LONG_DELAY_MS/2, r);
-//     }
-
     /**
      * Checks that timed f.get() returns the expected value, and does not
      * wait for the timeout to elapse before returning.
@@ -1448,15 +1490,21 @@
      * to terminate (using {@link Thread#join(long)}), else interrupts
      * the thread (in the hope that it may terminate later) and fails.
      */
-    void awaitTermination(Thread t, long timeoutMillis) {
+    void awaitTermination(Thread thread, long timeoutMillis) {
         try {
-            t.join(timeoutMillis);
+            thread.join(timeoutMillis);
         } catch (InterruptedException fail) {
             threadUnexpectedException(fail);
-        } finally {
-            if (t.getState() != Thread.State.TERMINATED) {
-                t.interrupt();
-                threadFail("timed out waiting for thread to terminate");
+        }
+        if (thread.getState() != Thread.State.TERMINATED) {
+            String detail = String.format(
+                    "timed out waiting for thread to terminate, thread=%s, state=%s" ,
+                    thread, thread.getState());
+            try {
+                threadFail(detail);
+            } finally {
+                // Interrupt thread __after__ having reported its stack trace
+                thread.interrupt();
             }
         }
     }
--- a/test/jdk/java/util/concurrent/tck/LinkedBlockingDequeTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/LinkedBlockingDequeTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -631,7 +631,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(SIZE, q.size());
@@ -673,7 +673,7 @@
         assertEquals(0, q.take());
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -690,26 +690,27 @@
                 q.put(new Object());
                 q.put(new Object());
                 long startTime = System.nanoTime();
+
                 assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS));
                 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -750,7 +751,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -802,29 +803,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
@@ -883,7 +881,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(SIZE, q.size());
@@ -918,7 +916,7 @@
         assertEquals(capacity - 1, q.take());
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -935,26 +933,27 @@
                 q.putFirst(new Object());
                 q.putFirst(new Object());
                 long startTime = System.nanoTime();
+
                 assertFalse(q.offerFirst(new Object(), timeoutMillis(), MILLISECONDS));
                 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offerFirst(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offerFirst(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offerFirst(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offerFirst(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -986,7 +985,7 @@
             }});
 
         await(threadStarted);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1027,7 +1026,7 @@
             }});
 
         await(threadStarted);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1077,7 +1076,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1118,29 +1117,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, q.pollFirst(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.pollFirst(LONG_DELAY_MS, MILLISECONDS);
+                    q.pollFirst(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.pollFirst(LONG_DELAY_MS, MILLISECONDS);
+                    q.pollFirst(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1164,7 +1160,7 @@
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.pollFirst(LONG_DELAY_MS, MILLISECONDS);
+                    q.pollFirst(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
 
@@ -1174,6 +1170,7 @@
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
+
                 assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
@@ -1182,7 +1179,7 @@
         assertTrue(q.offerFirst(zero, LONG_DELAY_MS, MILLISECONDS));
         assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
         barrier.await();
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1240,7 +1237,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(SIZE, q.size());
@@ -1282,7 +1279,7 @@
         assertEquals(0, q.take());
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -1299,24 +1296,25 @@
                 q.putLast(new Object());
                 q.putLast(new Object());
                 long startTime = System.nanoTime();
+
                 assertFalse(q.offerLast(new Object(), timeoutMillis(), MILLISECONDS));
                 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offerLast(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offerLast(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offerLast(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offerLast(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1358,7 +1356,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1399,30 +1397,27 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(SIZE - i - 1,
                                  q.pollLast(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.pollLast(LONG_DELAY_MS, MILLISECONDS);
+                    q.pollLast(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.pollLast(LONG_DELAY_MS, MILLISECONDS);
+                    q.pollLast(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
@@ -1447,7 +1442,7 @@
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
@@ -1468,7 +1463,7 @@
         assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
 
         barrier.await();
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
--- a/test/jdk/java/util/concurrent/tck/LinkedBlockingQueueTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/LinkedBlockingQueueTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -318,7 +318,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(SIZE, q.size());
@@ -360,7 +360,7 @@
         assertEquals(0, q.take());
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -376,28 +376,28 @@
             public void realRun() throws InterruptedException {
                 q.put(new Object());
                 q.put(new Object());
+                long startTime = System.nanoTime();
 
-                long startTime = System.nanoTime();
                 assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS));
                 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -438,7 +438,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -490,29 +490,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
--- a/test/jdk/java/util/concurrent/tck/LinkedTransferQueueTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/LinkedTransferQueueTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -254,7 +254,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -308,29 +308,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
@@ -344,16 +341,14 @@
         final BlockingQueue<Integer> q = populatedQueue(SIZE);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 Thread.currentThread().interrupt();
                 for (int i = 0; i < SIZE; ++i)
-                    assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+                    assertEquals(i, (int) q.poll(randomTimeout(), randomTimeUnit()));
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         awaitTermination(t);
@@ -982,25 +977,23 @@
 
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 Thread.currentThread().interrupt();
                 try {
-                    q.tryTransfer(new Object(), LONG_DELAY_MS, MILLISECONDS);
+                    q.tryTransfer(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.tryTransfer(new Object(), LONG_DELAY_MS, MILLISECONDS);
+                    q.tryTransfer(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
--- a/test/jdk/java/util/concurrent/tck/LongAccumulatorTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/LongAccumulatorTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -150,7 +150,7 @@
             = new LongAccumulator((x, y) -> x + y, 0L);
         final int nThreads = ThreadLocalRandom.current().nextInt(1, 5);
         final Phaser phaser = new Phaser(nThreads + 1);
-        final int incs = 1_000_000;
+        final int incs = expensiveTests ? 1_000_000 : 100_000;
         final long total = nThreads * incs/2L * (incs - 1); // Gauss
         final Runnable task = () -> {
             phaser.arriveAndAwaitAdvance();
--- a/test/jdk/java/util/concurrent/tck/MapTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/MapTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -122,6 +122,7 @@
      */
     public void testBug8186171() {
         if (!impl.supportsSetValue()) return;
+        if (!atLeastJava10()) return; // jdk9 is no longer maintained
         final ThreadLocalRandom rnd = ThreadLocalRandom.current();
         final boolean permitsNullValues = impl.permitsNullValues();
         final Object v1 = (permitsNullValues && rnd.nextBoolean())
--- a/test/jdk/java/util/concurrent/tck/PhaserTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/PhaserTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -480,7 +480,7 @@
     /**
      * awaitAdvanceInterruptibly blocks interruptibly
      */
-    public void testAwaitAdvanceInterruptibly_interruptible() throws InterruptedException {
+    public void testAwaitAdvanceInterruptibly_Interruptible() throws InterruptedException {
         final Phaser phaser = new Phaser(1);
         final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
 
@@ -505,14 +505,14 @@
             public void realRun() throws TimeoutException {
                 Thread.currentThread().interrupt();
                 try {
-                    phaser.awaitAdvanceInterruptibly(0, 2*LONG_DELAY_MS, MILLISECONDS);
+                    phaser.awaitAdvanceInterruptibly(0, randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    phaser.awaitAdvanceInterruptibly(0, 2*LONG_DELAY_MS, MILLISECONDS);
+                    phaser.awaitAdvanceInterruptibly(0, LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
@@ -520,8 +520,8 @@
 
         await(pleaseInterrupt);
         assertState(phaser, 0, 1, 1);
-        assertThreadBlocks(t1, Thread.State.WAITING);
-        assertThreadBlocks(t2, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t1, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t2, Thread.State.TIMED_WAITING);
         t1.interrupt();
         t2.interrupt();
         awaitTermination(t1);
--- a/test/jdk/java/util/concurrent/tck/PriorityBlockingQueueTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/PriorityBlockingQueueTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -346,7 +346,7 @@
     }
 
     /**
-     * timed offer does not time out
+     * Queue is unbounded, so timed offer never times out
      */
     public void testTimedOffer() {
         final PriorityBlockingQueue q = new PriorityBlockingQueue(2);
@@ -397,7 +397,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -449,29 +449,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
--- a/test/jdk/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -707,7 +707,7 @@
         Runnable waiter = new CheckedRunnable() { public void realRun() {
             threadsStarted.countDown();
             try {
-                MILLISECONDS.sleep(2 * LONG_DELAY_MS);
+                MILLISECONDS.sleep(LONGER_DELAY_MS);
             } catch (InterruptedException success) {}
             ran.getAndIncrement();
         }};
--- a/test/jdk/java/util/concurrent/tck/ScheduledExecutorTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ScheduledExecutorTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -666,7 +666,7 @@
         Runnable waiter = new CheckedRunnable() { public void realRun() {
             threadsStarted.countDown();
             try {
-                MILLISECONDS.sleep(2 * LONG_DELAY_MS);
+                MILLISECONDS.sleep(LONGER_DELAY_MS);
             } catch (InterruptedException success) {}
             ran.getAndIncrement();
         }};
--- a/test/jdk/java/util/concurrent/tck/SemaphoreTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/SemaphoreTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -38,7 +38,6 @@
 import java.util.Collection;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Semaphore;
-import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -220,24 +219,22 @@
     /**
      * timed tryAcquire times out
      */
-    public void testTryAcquire_timeout() {
-        final boolean fair = ThreadLocalRandom.current().nextBoolean();
+    public void testTryAcquire_timeout() throws InterruptedException {
+        final boolean fair = randomBoolean();
         final Semaphore s = new Semaphore(0, fair);
         final long startTime = System.nanoTime();
-        try { assertFalse(s.tryAcquire(timeoutMillis(), MILLISECONDS)); }
-        catch (InterruptedException e) { threadUnexpectedException(e); }
+        assertFalse(s.tryAcquire(timeoutMillis(), MILLISECONDS));
         assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
     }
 
     /**
      * timed tryAcquire(N) times out
      */
-    public void testTryAcquireN_timeout() {
-        final boolean fair = ThreadLocalRandom.current().nextBoolean();
+    public void testTryAcquireN_timeout() throws InterruptedException {
+        final boolean fair = randomBoolean();
         final Semaphore s = new Semaphore(2, fair);
         final long startTime = System.nanoTime();
-        try { assertFalse(s.tryAcquire(3, timeoutMillis(), MILLISECONDS)); }
-        catch (InterruptedException e) { threadUnexpectedException(e); }
+        assertFalse(s.tryAcquire(3, timeoutMillis(), MILLISECONDS));
         assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
     }
 
--- a/test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -45,7 +45,6 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 
@@ -166,7 +165,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -207,7 +206,7 @@
         catch (InterruptedException e) { threadUnexpectedException(e); }
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -217,32 +216,33 @@
      * timed offer times out if elements not taken
      */
     public void testTimedOffer() {
-        final boolean fair = ThreadLocalRandom.current().nextBoolean();
+        final boolean fair = randomBoolean();
         final SynchronousQueue q = new SynchronousQueue(fair);
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
                 long startTime = System.nanoTime();
+
                 assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS));
                 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -272,7 +272,7 @@
      * timed poll with nonzero timeout times out if no active putter
      */
     public void testTimedPoll() {
-        final boolean fair = ThreadLocalRandom.current().nextBoolean();
+        final boolean fair = randomBoolean();
         final SynchronousQueue q = new SynchronousQueue(fair);
         final long startTime = System.nanoTime();
         try { assertNull(q.poll(timeoutMillis(), MILLISECONDS)); }
@@ -285,7 +285,7 @@
      * after offer succeeds; on interruption throws
      */
     public void testTimedPollWithOffer() {
-        final boolean fair = ThreadLocalRandom.current().nextBoolean();
+        final boolean fair = randomBoolean();
         final SynchronousQueue q = new SynchronousQueue(fair);
         final CountDownLatch pleaseOffer = new CountDownLatch(1);
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
@@ -301,7 +301,7 @@
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
@@ -323,7 +323,7 @@
         assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
--- a/test/jdk/java/util/concurrent/tck/ThreadPoolExecutorSubclassTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ThreadPoolExecutorSubclassTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -796,7 +796,7 @@
         Runnable waiter = new CheckedRunnable() { public void realRun() {
             threadsStarted.countDown();
             try {
-                MILLISECONDS.sleep(2 * LONG_DELAY_MS);
+                MILLISECONDS.sleep(LONGER_DELAY_MS);
             } catch (InterruptedException success) {}
             ran.getAndIncrement();
         }};
@@ -1669,7 +1669,7 @@
             l.add(latchAwaitingStringTask(latch));
             l.add(null);
             try {
-                e.invokeAny(l, randomTimeout(), MILLISECONDS);
+                e.invokeAny(l, randomTimeout(), randomTimeUnit());
                 shouldThrow();
             } catch (NullPointerException success) {}
             latch.countDown();
--- a/test/jdk/java/util/concurrent/tck/ThreadPoolExecutorTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ThreadPoolExecutorTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -699,7 +699,7 @@
         Runnable waiter = new CheckedRunnable() { public void realRun() {
             threadsStarted.countDown();
             try {
-                MILLISECONDS.sleep(2 * LONG_DELAY_MS);
+                MILLISECONDS.sleep(LONGER_DELAY_MS);
             } catch (InterruptedException success) {}
             ran.getAndIncrement();
         }};
--- a/test/jdk/java/util/concurrent/tck/TimeUnitTest.java	Sat Sep 14 13:18:20 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/TimeUnitTest.java	Sun Sep 15 13:41:19 2019 +0200
@@ -56,243 +56,56 @@
         return new TestSuite(TimeUnitTest.class);
     }
 
-    // (loops to 88888 check increments at all time divisions.)
-
-    /**
-     * convert correctly converts sample values across the units
-     */
-    public void testConvert() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*60*60*24,
-                         SECONDS.convert(t, DAYS));
-            assertEquals(t*60*60,
-                         SECONDS.convert(t, HOURS));
-            assertEquals(t*60,
-                         SECONDS.convert(t, MINUTES));
-            assertEquals(t,
-                         SECONDS.convert(t, SECONDS));
-            assertEquals(t,
-                         SECONDS.convert(1000L*t, MILLISECONDS));
-            assertEquals(t,
-                         SECONDS.convert(1000000L*t, MICROSECONDS));
-            assertEquals(t,
-                         SECONDS.convert(1000000000L*t, NANOSECONDS));
-
-            assertEquals(1000L*t*60*60*24,
-                         MILLISECONDS.convert(t, DAYS));
-            assertEquals(1000L*t*60*60,
-                         MILLISECONDS.convert(t, HOURS));
-            assertEquals(1000L*t*60,
-                         MILLISECONDS.convert(t, MINUTES));
-            assertEquals(1000L*t,
-                         MILLISECONDS.convert(t, SECONDS));
-            assertEquals(t,
-                         MILLISECONDS.convert(t, MILLISECONDS));
-            assertEquals(t,
-                         MILLISECONDS.convert(1000L*t, MICROSECONDS));
-            assertEquals(t,
-                         MILLISECONDS.convert(1000000L*t, NANOSECONDS));
-
-            assertEquals(1000000L*t*60*60*24,
-                         MICROSECONDS.convert(t, DAYS));
-            assertEquals(1000000L*t*60*60,
-                         MICROSECONDS.convert(t, HOURS));
-            assertEquals(1000000L*t*60,
-                         MICROSECONDS.convert(t, MINUTES));
-            assertEquals(1000000L*t,
-                         MICROSECONDS.convert(t, SECONDS));
-            assertEquals(1000L*t,
-                         MICROSECONDS.convert(t, MILLISECONDS));
-            assertEquals(t,
-                         MICROSECONDS.convert(t, MICROSECONDS));
-            assertEquals(t,
-                         MICROSECONDS.convert(1000L*t, NANOSECONDS));
-
-            assertEquals(1000000000L*t*60*60*24,
-                         NANOSECONDS.convert(t, DAYS));
-            assertEquals(1000000000L*t*60*60,
-                         NANOSECONDS.convert(t, HOURS));
-            assertEquals(1000000000L*t*60,
-                         NANOSECONDS.convert(t, MINUTES));
-            assertEquals(1000000000L*t,
-                         NANOSECONDS.convert(t, SECONDS));
-            assertEquals(1000000L*t,
-                         NANOSECONDS.convert(t, MILLISECONDS));
-            assertEquals(1000L*t,
-                         NANOSECONDS.convert(t, MICROSECONDS));
-            assertEquals(t,
-                         NANOSECONDS.convert(t, NANOSECONDS));
+    void testConversion(TimeUnit x, TimeUnit y, long n, long expected) {
+        assertEquals(expected, x.convert(n, y));
+        switch (x) {
+        case NANOSECONDS:  assertEquals(expected, y.toNanos(n));   break;
+        case MICROSECONDS: assertEquals(expected, y.toMicros(n));  break;
+        case MILLISECONDS: assertEquals(expected, y.toMillis(n));  break;
+        case SECONDS:      assertEquals(expected, y.toSeconds(n)); break;
+        case MINUTES:      assertEquals(expected, y.toMinutes(n)); break;
+        case HOURS:        assertEquals(expected, y.toHours(n));   break;
+        case DAYS:         assertEquals(expected, y.toDays(n));    break;
+        default: throw new AssertionError();
         }
 
-        for (TimeUnit x : TimeUnit.values()) {
-            long[] zs = {
-                0, 1, -1,
-                Integer.MAX_VALUE, Integer.MIN_VALUE,
-                Long.MAX_VALUE, Long.MIN_VALUE,
-            };
-            for (long z : zs) assertEquals(z, x.convert(z, x));
-        }
+        if (n > 0) testConversion(x, y, -n, -expected);
     }
 
-    /**
-     * toNanos correctly converts sample values in different units to
-     * nanoseconds
-     */
-    public void testToNanos() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*1000000000L*60*60*24,
-                         DAYS.toNanos(t));
-            assertEquals(t*1000000000L*60*60,
-                         HOURS.toNanos(t));
-            assertEquals(t*1000000000L*60,
-                         MINUTES.toNanos(t));
-            assertEquals(1000000000L*t,
-                         SECONDS.toNanos(t));
-            assertEquals(1000000L*t,
-                         MILLISECONDS.toNanos(t));
-            assertEquals(1000L*t,
-                         MICROSECONDS.toNanos(t));
-            assertEquals(t,
-                         NANOSECONDS.toNanos(t));
+    void testConversion(TimeUnit x, TimeUnit y) {
+        long ratio = x.toNanos(1)/y.toNanos(1);
+        assertTrue(ratio > 0);
+        long[] ns = { 0, 1, 2, Long.MAX_VALUE/ratio, Long.MIN_VALUE/ratio };
+        for (long n : ns) {
+            testConversion(y, x, n, n * ratio);
+            long[] ks = { n * ratio, n * ratio + 1, n * ratio - 1 };
+            for (long k : ks) {
+                testConversion(x, y, k, k / ratio);
+            }
         }
     }
 
     /**
-     * toMicros correctly converts sample values in different units to
-     * microseconds
-     */
-    public void testToMicros() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*1000000L*60*60*24,
-                         DAYS.toMicros(t));
-            assertEquals(t*1000000L*60*60,
-                         HOURS.toMicros(t));
-            assertEquals(t*1000000L*60,
-                         MINUTES.toMicros(t));
-            assertEquals(1000000L*t,
-                         SECONDS.toMicros(t));
-            assertEquals(1000L*t,
-                         MILLISECONDS.toMicros(t));
-            assertEquals(t,
-                         MICROSECONDS.toMicros(t));
-            assertEquals(t,
-                         NANOSECONDS.toMicros(t*1000L));
-        }
-    }
-
-    /**
-     * toMillis correctly converts sample values in different units to
-     * milliseconds
+     * Conversion methods correctly convert sample values
      */
-    public void testToMillis() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*1000L*60*60*24,
-                         DAYS.toMillis(t));
-            assertEquals(t*1000L*60*60,
-                         HOURS.toMillis(t));
-            assertEquals(t*1000L*60,
-                         MINUTES.toMillis(t));
-            assertEquals(1000L*t,
-                         SECONDS.toMillis(t));
-            assertEquals(t,
-                         MILLISECONDS.toMillis(t));
-            assertEquals(t,
-                         MICROSECONDS.toMillis(t*1000L));
-            assertEquals(t,
-                         NANOSECONDS.toMillis(t*1000000L));
-        }
-    }
-
-    /**
-     * toSeconds correctly converts sample values in different units to
-     * seconds
-     */
-    public void testToSeconds() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*60*60*24,
-                         DAYS.toSeconds(t));
-            assertEquals(t*60*60,
-                         HOURS.toSeconds(t));
-            assertEquals(t*60,
-                         MINUTES.toSeconds(t));
-            assertEquals(t,
-                         SECONDS.toSeconds(t));
-            assertEquals(t,
-                         MILLISECONDS.toSeconds(t*1000L));
-            assertEquals(t,
-                         MICROSECONDS.toSeconds(t*1000000L));
-            assertEquals(t,
-                         NANOSECONDS.toSeconds(t*1000000000L));
-        }
-    }
+    public void testConversions() {
+        // Sanity check
+        assertEquals(1, NANOSECONDS.toNanos(1));
+        assertEquals(1000L * NANOSECONDS.toNanos(1), MICROSECONDS.toNanos(1));
+        assertEquals(1000L * MICROSECONDS.toNanos(1), MILLISECONDS.toNanos(1));
+        assertEquals(1000L * MILLISECONDS.toNanos(1), SECONDS.toNanos(1));
+        assertEquals(60L * SECONDS.toNanos(1), MINUTES.toNanos(1));
+        assertEquals(60L * MINUTES.toNanos(1), HOURS.toNanos(1));
+        assertEquals(24L * HOURS.toNanos(1), DAYS.toNanos(1));
 
-    /**
-     * toMinutes correctly converts sample values in different units to
-     * minutes
-     */
-    public void testToMinutes() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*60*24,
-                         DAYS.toMinutes(t));
-            assertEquals(t*60,
-                         HOURS.toMinutes(t));
-            assertEquals(t,
-                         MINUTES.toMinutes(t));
-            assertEquals(t,
-                         SECONDS.toMinutes(t*60));
-            assertEquals(t,
-                         MILLISECONDS.toMinutes(t*1000L*60));
-            assertEquals(t,
-                         MICROSECONDS.toMinutes(t*1000000L*60));
-            assertEquals(t,
-                         NANOSECONDS.toMinutes(t*1000000000L*60));
+        for (TimeUnit x : TimeUnit.values()) {
+            assertEquals(x.toNanos(1), NANOSECONDS.convert(1, x));
         }
-    }
 
-    /**
-     * toHours correctly converts sample values in different units to
-     * hours
-     */
-    public void testToHours() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*24,
-                         DAYS.toHours(t));
-            assertEquals(t,
-                         HOURS.toHours(t));
-            assertEquals(t,
-                         MINUTES.toHours(t*60));
-            assertEquals(t,
-                         SECONDS.toHours(t*60*60));
-            assertEquals(t,
-                         MILLISECONDS.toHours(t*1000L*60*60));
-            assertEquals(t,
-                         MICROSECONDS.toHours(t*1000000L*60*60));
-            assertEquals(t,
-                         NANOSECONDS.toHours(t*1000000000L*60*60));
-        }
-    }
-
-    /**
-     * toDays correctly converts sample values in different units to
-     * days
-     */
-    public void testToDays() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t,
-                         DAYS.toDays(t));
-            assertEquals(t,
-                         HOURS.toDays(t*24));
-            assertEquals(t,
-                         MINUTES.toDays(t*60*24));
-            assertEquals(t,
-                         SECONDS.toDays(t*60*60*24));
-            assertEquals(t,
-                         MILLISECONDS.toDays(t*1000L*60*60*24));
-            assertEquals(t,
-                         MICROSECONDS.toDays(t*1000000L*60*60*24));
-            assertEquals(t,
-                         NANOSECONDS.toDays(t*1000000000L*60*60*24));
-        }
+        for (TimeUnit x : TimeUnit.values())
+            for (TimeUnit y : TimeUnit.values())
+                if (x.toNanos(1) >= y.toNanos(1))
+                    testConversion(x, y);
     }
 
     /**
@@ -494,14 +307,21 @@
      * toString returns name of unit
      */
     public void testToString() {
+        assertEquals("NANOSECONDS", NANOSECONDS.toString());
+        assertEquals("MICROSECONDS", MICROSECONDS.toString());
+        assertEquals("MILLISECONDS", MILLISECONDS.toString());
         assertEquals("SECONDS", SECONDS.toString());
+        assertEquals("MINUTES", MINUTES.toString());
+        assertEquals("HOURS", HOURS.toString());
+        assertEquals("DAYS", DAYS.toString());
     }
 
     /**
      * name returns name of unit
      */
     public void testName() {
-        assertEquals("SECONDS", SECONDS.name());
+        for (TimeUnit x : TimeUnit.values())
+            assertEquals(x.toString(), x.name());
     }
 
     /**
@@ -512,10 +332,8 @@
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
                 Object o = new Object();
-                TimeUnit tu = MILLISECONDS;
-
                 try {
-                    tu.timedWait(o, LONG_DELAY_MS);
+                    MILLISECONDS.timedWait(o, LONGER_DELAY_MS);
                     threadShouldThrow();
                 } catch (IllegalMonitorStateException success) {}
             }});
@@ -531,12 +349,11 @@
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
                 Object o = new Object();
-                TimeUnit tu = MILLISECONDS;
 
                 Thread.currentThread().interrupt();
                 try {
                     synchronized (o) {
-                        tu.timedWait(o, LONG_DELAY_MS);
+                        MILLISECONDS.timedWait(o, LONGER_DELAY_MS);
                     }
                     shouldThrow();
                 } catch (InterruptedException success) {}
@@ -545,7 +362,7 @@
                 pleaseInterrupt.countDown();
                 try {
                     synchronized (o) {
-                        tu.timedWait(o, LONG_DELAY_MS);
+                        MILLISECONDS.timedWait(o, LONGER_DELAY_MS);
                     }
                     shouldThrow();
                 } catch (InterruptedException success) {}
@@ -553,7 +370,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -565,28 +382,27 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         final Thread s = newStartedThread(new CheckedInterruptedRunnable() {
             public void realRun() throws InterruptedException {
-                Thread.sleep(LONG_DELAY_MS);
+                Thread.sleep(LONGER_DELAY_MS);
             }});
         final Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                TimeUnit tu = MILLISECONDS;
                 Thread.currentThread().interrupt();
                 try {
-                    tu.timedJoin(s, LONG_DELAY_MS);
+                    MILLISECONDS.timedJoin(s, LONGER_DELAY_MS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    tu.timedJoin(s, LONG_DELAY_MS);
+                    MILLISECONDS.timedJoin(s, LONGER_DELAY_MS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         s.interrupt();
@@ -594,35 +410,46 @@
     }
 
     /**
-     * timedSleep throws InterruptedException when interrupted
+     * timeUnit.sleep throws InterruptedException when interrupted
      */
     public void testTimedSleep_Interruptible() {
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                TimeUnit tu = MILLISECONDS;
                 Thread.currentThread().interrupt();
                 try {
-                    tu.sleep(LONG_DELAY_MS);
+                    MILLISECONDS.sleep(LONGER_DELAY_MS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    tu.sleep(LONG_DELAY_MS);
+                    MILLISECONDS.sleep(LONGER_DELAY_MS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
 
     /**
+     * timeUnit.sleep(x) for x <= 0 does not sleep at all.
+     */
+    public void testTimedSleep_nonPositive() throws InterruptedException {
+        boolean interrupt = randomBoolean();
+        if (interrupt) Thread.currentThread().interrupt();
+        randomTimeUnit().sleep(0L);
+        randomTimeUnit().sleep(-1L);
+        randomTimeUnit().sleep(Long.MIN_VALUE);
+        if (interrupt) assertTrue(Thread.interrupted());
+    }
+
+    /**
      * a deserialized/reserialized unit is the same instance
      */
     public void testSerialization() throws Exception {