Thread safety ensures that multiple threads can access shared resources concurrently without causing data inconsistency or corruption. Here are common methods to achieve thread safety in Java:
- Synchronized Blocks/Methods:
Use the synchronized
keyword to lock the critical section so only one thread can execute it at a time.
java
public synchronized void increment() {
count++;
}
Pitfall: Overusing synchronized
can lead to performance bottlenecks due to thread contention.
- Locks (
java.util.concurrent.locks.Lock
):
Use Lock
objects for more fine-grained control over thread synchronization compared to synchronized
.
java
Lock lock = new ReentrantLock();
lock.lock();
try {
// Critical section
} finally {
lock.unlock();
}
- Atomic Classes (
java.util.concurrent.atomic
):
Use atomic classes like AtomicInteger
, AtomicBoolean
, etc., which provide lock-free, thread-safe operations for simple variables.
java
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();
- Thread-safe Collections (
java.util.concurrent
):
Use concurrent collections like ConcurrentHashMap
, CopyOnWriteArrayList
, etc., which are designed to handle concurrent access.
java
ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>();
map.put(1, "Value");
Things to keep in mind:
1. Minimize the critical section size to reduce performance overhead.
2. Avoid excessive synchronization to prevent deadlock and contention issues.
These approaches help ensure thread safety while balancing performance and complexity in Java applications.