Java并发编程是构建高性能系统的核心技能,但也伴随着复杂的挑战。本文通过实际代码示例,系统讲解线程安全、死锁、资源竞争等常见问题的解决方案,并深入探讨如何利用Java并发工具包(java.util.concurrent)构建健壮的并发程序。
一、线程安全问题与解决方案
1.1 共享资源的竞态条件(Race Condition)
问题现象:
多个线程同时修改共享变量,导致数据不一致。
public class Counter {
private int count = 0;
public void increment() {
count++; // 非原子操作
}
public int getCount() {
return count;
}
}
// 测试代码
public class RaceConditionTest {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Expected: 20000, Actual: " + counter.getCount());
}
}
输出结果:
Expected: 20000, Actual: 18437
解决方案:
使用synchronized
关键字
public class SafeCounter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
使用ReentrantLock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SafeCounter {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}
使用AtomicInteger
import java.util.concurrent.atomic.AtomicInteger;
public class SafeCounter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // 原子操作
}
public int getCount() {
return count.get();
}
}
二、死锁问题与避免策略
2.1 死锁产生的条件
四个必要条件:
- 互斥(Mutual Exclusion)
- 请求与保持(Hold and Wait)
- 不可抢占(No Preemption)