Working with Synchronization
1. Using synchronized Keyword
Example: synchronized
public synchronized void increment() { count++; } // intrinsic lock on this
public void update() {
synchronized (lock) { ... } // explicit lock object
}
| Form | Lock |
|---|---|
| Instance method | this |
| Static method | Class object |
| Block | Specified object |
2. Synchronizing Methods
| Aspect | Detail |
|---|---|
| Granularity | Whole method body |
| Visibility | public synchronized exposes lock to outside (avoid) |
3. Synchronizing Blocks
| Practice | Detail |
|---|---|
| Private lock | private final Object lock = new Object(); |
| Minimize scope | Hold for shortest possible time |
4. Understanding Intrinsic Locks (Monitor)
| Property | Detail |
|---|---|
| Reentrant | Same thread can re-acquire |
| Mutual exclusion | Only one thread holds lock |
| Visibility | Establishes happens-before |
5. Using Lock Interface
Example: Lock
private final Lock lock = new ReentrantLock();
public void update() {
lock.lock();
try { ... } finally { lock.unlock(); }
}
| Method | Use |
|---|---|
lock() | Block until acquired |
tryLock() / tryLock(t, u) | Non-blocking / timed |
lockInterruptibly() | Responds to interruption |
unlock() | Always in finally |
6. Using ReentrantLock
| Feature | Detail |
|---|---|
| Fairness | new ReentrantLock(true) = FIFO |
| Hold count | getHoldCount() |
| Conditions | newCondition() |
7. Using ReadWriteLock
| Aspect | Detail |
|---|---|
| Reads concurrent | Multiple readers OK if no writer |
| Writes exclusive | One writer, no readers |
| Best for | Read-heavy workloads |
| Modern alternative | StampedLock with optimistic reads |
8. Using StampedLock JAVA 8+
Example: Optimistic read
StampedLock sl = new StampedLock();
long stamp = sl.tryOptimisticRead();
double curX = x, curY = y;
if (!sl.validate(stamp)) {
stamp = sl.readLock();
try { curX = x; curY = y; } finally { sl.unlockRead(stamp); }
}
| Mode | Detail |
|---|---|
| Write | Exclusive |
| Read | Shared |
| Optimistic read | No lock; validate after |
| Limitation | Not reentrant |
9. Using volatile Keyword
| Guarantee | Detail |
|---|---|
| Visibility | Writes visible to other threads |
| Ordering | Prevents reordering across volatile access |
| No atomicity | ++ still NOT atomic on volatile |
| Use case | Status flags, double-checked locking |
10. Understanding Atomic Operations
| Class | Use |
|---|---|
AtomicInteger / Long / Boolean | Atomic primitives |
AtomicReference<T> | Atomic object reference |
AtomicIntegerArray | Element-wise atomic |
| Operations | incrementAndGet, compareAndSet, updateAndGet |
| High contention | Use LongAdder/LongAccumulator instead |
11. Using Atomic Classes
Example: Atomic counter
AtomicLong counter = new AtomicLong();
counter.incrementAndGet();
counter.compareAndSet(10, 20); // CAS
counter.updateAndGet(v -> v * 2);
LongAdder hits = new LongAdder(); // better under high contention
hits.increment();
long total = hits.sum();
| Class | When |
|---|---|
AtomicLong | Low/medium contention |
LongAdder | High write contention; eventual consistent reads |
LongAccumulator | Custom merge function |
12. Avoiding Deadlocks
| Strategy | Detail |
|---|---|
| Lock ordering | Always acquire in same global order |
Use tryLock with timeout | Back off and retry |
| Avoid nested locks | Hold one at a time |
| Detection | jstack shows deadlock |
13. Understanding Memory Model (JMM)
| Concept | Detail |
|---|---|
| Happens-before | Ordering guarantee for visibility |
| Synchronization actions | Lock/unlock, volatile read/write, thread start/join |
| Final fields | Safely published if not exposed before constructor finishes |
| No JMM violation tools | JCStress for testing |