Design
Documentation
@GuardedBy annotation is used?volatile is justified?volatile nor annotated with @GuardedBy has a comment?Insufficient synchronization
@GET/@POST methods, Jetty Filters and Handlers are thread-safe?DateFormat.parse() and format() are synchronized?Excessive thread safety
get() and set() are called?ReentrantLock (ReentrantReadWriteLock, Semaphore) needs to be fair?Race conditions
put() or remove() calls on a ConcurrentMap (or Cache) after get() or containsKey()?coll.toArray(new E[coll.size()]) is not called on a synchronized collection?invalidate(key) and get() calls on Guava's loading Cache?Cache.put() is not used (nor exposed in the own Cache interface)?Collections.synchronized*() collection is protected by a lock?Testing
Random instance is not used from concurrent test workers?Locks
LifecycleLock instead of a standard lock in a lifecycled object?wait (await) calls?Monitor instead of a lock with conditional wait (await) calls?synchronized instead of a ReentrantLock?lock() is called outside of try {}? No statements between lock() and try {}?Avoiding deadlocks
ConcurrentHashMap's methods (incl. get()) in compute()-like lambdas on the same map?Improving scalability
ConcurrentHashMap.compute() or Guava's Striped for per-key locking?ClassValue instead of ConcurrentHashMap<Class, ...>?ReadWriteLock (or StampedLock) instead of a simple lock?StampedLock is used instead of ReadWriteLock when reentrancy is not needed?LongAdder instead of an AtomicLong for a “hot field”?Lazy initialization and double-checked locking
Non-blocking and partially blocking code
Threads and Executors
Execs to create an ExecutorService?ExecutorService instead of creating a new Thread each time some method is called?ForkJoinPool or in a parallel Stream pipeline?FJP.commonPool() instead of a custom thread pool?ExecutorService is shutdown explicitly?Parallel Streams
Thread interruption and Future cancellation
InterruptedException with another exception?InterruptedException is swallowed only in the following kinds of methods:Runnable.run(), Callable.call(), or methods to be passed to executors as lambda tasks; orInterruptedException swallowing is documented for a method?Uninterruptibles to avoid InterruptedException swallowing?Future is canceled upon catching an InterruptedException or a TimeoutException on get()?Time
nanoTime() values are compared in an overflow-aware manner?currentTimeMillis() is not used to measure time intervals and timeouts?TimeUnit?Thread safety of Cleaners and native code
close() is concurrently idempotent in a class with a Cleaner or finalize()?reachabilityFence() in a class with a Cleaner or finalize()?Cleaner or finalize() is used for real cleanup, not mere reporting? # Lk.D1. Is it possible to use Druid's LifecycleLock utility instead of a standard lock and “started” flag in lifecycled objects with start() and stop() methods? See the Javadoc comment for LifecycleLock for more details.
# TE.D1. Are Threads created directly or via a ThreadFactory configured to be daemon via setDaemon(true)? Note that by default, ThreadFactories constructed via Execs.makeThreadFactory() methods create daemon threads already.
# TE.D2. Is it possible to use one of the static factory methods in Druid‘s Execs utility class to create an ExecutorService instead of Java’s standard ExecutorServices? This is recommended because Execs configure ThreadFactories to create daemon threads by default, as required by the previous item.