Master thread safety, synchronization, locks, concurrent collections, atomic classes, and thread-safe code patterns for the OCP 21 exam.
Table of Contents
1. Thread Safety
Thread safety ensures that shared data can be safely accessed by multiple threads without data corruption or inconsistent state.
1.1 Race Conditions
Example:
// NOT thread-safe
class Counter {
private int count = 0;
public void increment() {
count++; // Race condition - not atomic
}
public int getCount() {
return count;
}
}
// Thread-safe version
class SafeCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
2. Synchronization
2.1 Synchronized Methods
Example:
class Example {
private int value = 0;
// Synchronized instance method
public synchronized void increment() {
value++;
}
// Synchronized static method
public static synchronized void staticMethod() {
// Synchronizes on Class object
}
}
2.2 Synchronized Blocks
Example:
class Example {
private final Object lock = new Object();
private int value = 0;
public void increment() {
synchronized (lock) { // Synchronize on specific object
value++;
}
}
public void method() {
synchronized (this) { // Synchronize on instance
// Critical section
}
}
}
3. Lock Interface
The Lock interface provides more flexible locking than synchronized.
3.1 ReentrantLock
Example:
import java.util.concurrent.locks.ReentrantLock;
class Example {
private final ReentrantLock lock = new ReentrantLock();
private int value = 0;
public void increment() {
lock.lock(); // Acquire lock
try {
value++;
} finally {
lock.unlock(); // Always release in finally
}
}
// Try lock with timeout
public boolean tryIncrement() {
try {
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
value++;
return true;
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return false;
}
}
3.2 ReadWriteLock
Example:
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class DataStore {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private String data = "Initial";
public String read() {
lock.readLock().lock();
try {
return data; // Multiple readers can read simultaneously
} finally {
lock.readLock().unlock();
}
}
public void write(String newData) {
lock.writeLock().lock();
try {
data = newData; // Only one writer at a time
} finally {
lock.writeLock().unlock();
}
}
}
4. Atomic Classes
Atomic classes provide thread-safe operations on single variables without synchronization.
4.1 AtomicInteger and AtomicLong
Example:
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
// Thread-safe counter
class Counter {
private final AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // Atomic operation
}
public int get() {
return count.get();
}
// Compare and set
public boolean compareAndSet(int expected, int update) {
return count.compareAndSet(expected, update);
}
}
// AtomicLong for long values
AtomicLong atomicLong = new AtomicLong(0L);
atomicLong.addAndGet(10);
4.2 AtomicReference
Example:
import java.util.concurrent.atomic.AtomicReference;
AtomicReference<String> ref = new AtomicReference<>("Initial");
// Update atomically
ref.set("New Value");
// Compare and set
boolean updated = ref.compareAndSet("Initial", "Updated");
// Get and set
String oldValue = ref.getAndSet("New Value");
5. Volatile Keyword
The volatile keyword ensures visibility of changes across threads but does not provide atomicity.
5.1 Volatile Variables
Example:
class Example {
private volatile boolean flag = false;
public void setFlag() {
flag = true; // Write is immediately visible to all threads
}
public boolean getFlag() {
return flag; // Always reads latest value
}
}
// Volatile ensures visibility but NOT atomicity
// For compound operations, use synchronized or atomic classes
private volatile int count = 0;
public void increment() {
count++; // NOT atomic - still needs synchronization!
6. Exam Key Points
Critical Concepts for OCP 21 Exam:
- Thread Safety: Code safe for concurrent access
- Race Condition: When multiple threads access shared data unsafely
- synchronized: Ensures only one thread executes critical section
- synchronized method: Locks on instance (or Class for static)
- synchronized block: Locks on specified object
- ReentrantLock: More flexible than synchronized
- ReadWriteLock: Allows multiple readers or single writer
- Atomic Classes: Thread-safe operations without synchronization
- AtomicInteger: Thread-safe integer operations
- compareAndSet: Atomic compare-and-swap operation
- volatile: Ensures visibility, not atomicity
- Lock Ordering: Always acquire locks in same order to avoid deadlock
- Deadlock: When threads wait for each other indefinitely
0 Comments