I'd reach for the enum singleton or the lazy-holder idiom rather than hand-rolling double-checked locking, because the holder gets laziness and thread-safety free via the JVM's class-init guarantee and enum is additionally immune to reflection and serialization attacks.
The anti-pattern critique is really about the static getInstance() global access point: it is hidden global mutable state that couples callers invisibly, leaks between tests, and resists mocking. The clean modern answer is to let a DI container own the single instance (Spring's default singleton scope) so you keep one-instance economy but inject it, preserving testability.
- Writing double-checked locking without volatile.
- Not mentioning the enum singleton or holder idiom.