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.