Prompt
When managing state accessed by multiple threads, ensure thread safety through appropriate synchronization mechanisms:
- Use thread-safe collections for multi-threaded access:
// Incorrect private List<TraceListener> listeners; // Correct private final List<TraceListener> listeners = new CopyOnWriteArrayList<>(); - Implement proper lazy initialization with either:
- Volatile fields with double-checked locking
- The
LazyValueabstraction - Initialization at construction time with final fields ```java // Incorrect - not thread-safe private TraceManager traceManager;
public TraceManager getTraceManager() { if (traceManager == null) { traceManager = new TraceManager(); // Race condition! } return traceManager; }
// Correct - thread-safe with volatile private volatile TraceManager traceManager;
public TraceManager getTraceManager() { TraceManager result = traceManager; if (result == null) { synchronized (this) { result = traceManager; if (result == null) { traceManager = result = new TraceManager(); } } } return result; } ```
- For bit flag operations, use atomic operations rather than separate atomic fields:
// Correct pattern for concurrent bit flag operations private boolean set(byte bitMask) { byte state = this.state; for (;;) { if ((state & bitMask) != 0) { return false; } final byte newState = (byte) (state | bitMask); // Use compareAndExchange for atomicity byte oldState = STATE_UPDATER.compareAndExchange(this, state, newState); if (oldState == state) { return true; } state = oldState; } } - Avoid storing shared mutable state in fields accessed by concurrent operations:
// Incorrect - potential race condition private static AuthDevUIRecorder recorder; @BuildStep void doSomething(AuthDevUIRecorder recorder) { AuthProcessor.recorder = recorder; // Multiple build steps might race } // Correct - pass local parameters @BuildStep void doSomething(AuthDevUIRecorder recorder) { performOperation(recorder); }