Understand thread safety, synchronization, and atomic methods to prevent data corruption and race conditions in concurrent Java applications.
Thread safety ensures that your code works correctly when accessed by multiple threads simultaneously. Understanding memory architecture is key to thread safety.
Key concepts:
// Thread-unsafe counter example
public class Counter {
private int count = 0;
public void increment() {
count++; // This is not atomic!
}
public int getCount() {
return count;
}
}
Java provides synchronization mechanisms to prevent race conditions. The synchronized keyword ensures that only one thread can execute a method or block at a time.
Important synchronization concepts:
// Thread-safe counter using synchronized methods
public class ThreadSafeCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
// Thread-safe counter using synchronized block
public class AnotherThreadSafeCounter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized(lock) {
count++;
}
}
public int getCount() {
synchronized(lock) {
return count;
}
}
}
Java provides atomic classes for common operations that need to be thread-safe. Additionally, immutable objects are inherently thread-safe because their state cannot change after creation.
Thread-safe strategies:
// Using atomic classes
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicCounter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
// Immutable class example
public final class ImmutablePoint {
private final int x;
private final int y;
public ImmutablePoint(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
// No setters - state cannot be changed
}