线程同步
2026/1/15大约 3 分钟
线程同步
为什么需要同步
多线程访问共享资源时,如果没有同步机制,会导致数据不一致问题。
public class Counter {
private int count = 0;
public void increment() {
count++; // 非原子操作:读取 -> 加1 -> 写入
}
public int getCount() {
return count;
}
}
// 多线程环境下,最终结果可能小于预期synchronized 关键字
同步方法
public class Counter {
private int count = 0;
// 同步实例方法,锁是 this
public synchronized void increment() {
count++;
}
// 同步静态方法,锁是 Class 对象
public static synchronized void staticMethod() {
// ...
}
}同步代码块
public class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) { // 指定锁对象
count++;
}
}
public void decrement() {
synchronized (this) { // 使用 this 作为锁
count--;
}
}
}synchronized 原理
锁升级过程:
- 无锁 → 偏向锁 → 轻量级锁 → 重量级锁
Lock 接口
ReentrantLock 基本使用
public class Counter {
private int count = 0;
private final ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock(); // 必须在 finally 中释放锁
}
}
}tryLock() - 尝试获取锁
if (lock.tryLock()) {
try {
// 获取到锁,执行操作
} finally {
lock.unlock();
}
} else {
// 未获取到锁,执行其他逻辑
}
// 带超时的 tryLock
if (lock.tryLock(1, TimeUnit.SECONDS)) {
// ...
}公平锁 vs 非公平锁
// 公平锁:按照请求顺序获取锁
ReentrantLock fairLock = new ReentrantLock(true);
// 非公平锁(默认):允许插队,性能更好
ReentrantLock unfairLock = new ReentrantLock(false);Condition 条件变量
public class BoundedBuffer<T> {
private final Object[] items = new Object[100];
private int putIndex, takeIndex, count;
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
public void put(T item) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
notFull.await(); // 等待不满
}
items[putIndex] = item;
if (++putIndex == items.length) putIndex = 0;
count++;
notEmpty.signal(); // 通知不空
} finally {
lock.unlock();
}
}
@SuppressWarnings("unchecked")
public T take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
notEmpty.await(); // 等待不空
}
Object item = items[takeIndex];
if (++takeIndex == items.length) takeIndex = 0;
count--;
notFull.signal(); // 通知不满
return (T) item;
} finally {
lock.unlock();
}
}
}ReadWriteLock 读写锁
适用于读多写少的场景,读锁可以共享,写锁互斥。
public class Cache<K, V> {
private final Map<K, V> map = new HashMap<>();
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
public V get(K key) {
readLock.lock();
try {
return map.get(key);
} finally {
readLock.unlock();
}
}
public void put(K key, V value) {
writeLock.lock();
try {
map.put(key, value);
} finally {
writeLock.unlock();
}
}
}volatile 关键字
可见性
public class VolatileExample {
private volatile boolean running = true;
public void stop() {
running = false; // 修改对其他线程立即可见
}
public void run() {
while (running) {
// 如果不用 volatile,可能永远看不到 running 的变化
}
}
}禁止指令重排
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
// volatile 防止指令重排
// 没有 volatile,可能先赋值再初始化
instance = new Singleton();
}
}
}
return instance;
}
}volatile vs synchronized
| 特性 | volatile | synchronized |
|---|---|---|
| 原子性 | 不保证 | 保证 |
| 可见性 | 保证 | 保证 |
| 有序性 | 保证 | 保证 |
| 阻塞 | 不会 | 会 |
| 适用场景 | 状态标志 | 复合操作 |
原子类
AtomicInteger
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet(); // ++count
count.getAndIncrement(); // count++
count.addAndGet(5); // count += 5
count.compareAndSet(5, 10); // CAS 操作AtomicReference
AtomicReference<User> userRef = new AtomicReference<>(new User("Tom"));
User oldUser = userRef.get();
User newUser = new User("Jerry");
userRef.compareAndSet(oldUser, newUser);LongAdder(高并发计数器)
// 比 AtomicLong 性能更好,适合高并发写入场景
LongAdder counter = new LongAdder();
counter.increment();
counter.add(10);
long sum = counter.sum();synchronized vs Lock 对比
| 特性 | synchronized | Lock |
|---|---|---|
| 获取锁 | 自动 | 手动 lock() |
| 释放锁 | 自动 | 手动 unlock() |
| 可中断 | 不可 | lockInterruptibly() |
| 超时获取 | 不可 | tryLock(timeout) |
| 公平锁 | 不可 | 可配置 |
| 条件变量 | 单个 | 多个 Condition |
| 性能 | JDK6 后优化,差距不大 | 差距不大 |