线程同步
线程同步是并发编程的核心,用于控制多个线程对共享资源的访问,保证数据一致性。
1. synchronized 关键字
synchronized 是 Java 中最基本的同步机制,它可以保证同一时刻只有一个线程执行同步代码。
1.1 同步方法
java
public class Counter {
private int count = 0;
// 同步实例方法,锁对象是 this
public synchronized void increment() {
count++;
}
// 同步静态方法,锁对象是 Class 对象
public static synchronized void staticMethod() {
// ...
}
public int getCount() {
return count;
}
}1.2 同步代码块
java
public class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
public void decrement() {
synchronized (this) {
count--;
}
}
}1.3 锁对象总结
| 用法 | 锁对象 |
|---|---|
synchronized void method() | this(当前实例) |
static synchronized void method() | Class 对象 |
synchronized (object) | 指定对象 |
synchronized (this) | 当前实例 |
synchronized (ClassName.class) | Class 对象 |
2. volatile 关键字
volatile 保证变量的可见性和有序性,但不保证原子性。
java
public class VolatileExample {
private volatile boolean running = true;
public void stop() {
running = false;
}
public void run() {
while (running) {
// 由于 volatile,能够及时看到 running 的变化
}
}
}2.1 volatile 的作用
| 特性 | 说明 |
|---|---|
| 可见性 | 一个线程修改了 volatile 变量,其他线程能立即看到 |
| 有序性 | 禁止指令重排序优化 |
| 原子性 | ❌ 不保证(count++ 不是原子操作) |
2.2 适用场景
java
// ✅ 适合:状态标志
private volatile boolean shutdown = false;
// ✅ 适合:单次赋值
private volatile Config config;
// ❌ 不适合:复合操作
private volatile int count;
count++; // 不是原子操作!3. Lock 接口
java.util.concurrent.locks.Lock 提供了比 synchronized 更灵活的锁机制。
3.1 ReentrantLock
java
import java.util.concurrent.locks.*;
public class LockExample {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock(); // 必须在 finally 中释放锁
}
}
// 尝试获取锁
public boolean tryIncrement() {
if (lock.tryLock()) {
try {
count++;
return true;
} finally {
lock.unlock();
}
}
return false;
}
// 可中断的锁获取
public void interruptibleIncrement() throws InterruptedException {
lock.lockInterruptibly();
try {
count++;
} finally {
lock.unlock();
}
}
}3.2 synchronized vs Lock
| 特性 | synchronized | Lock |
|---|---|---|
| 释放锁 | 自动释放 | 手动调用 unlock() |
| 可中断 | ❌ | ✅ lockInterruptibly() |
| 尝试获取 | ❌ | ✅ tryLock() |
| 超时获取 | ❌ | ✅ tryLock(time, unit) |
| 公平锁 | ❌ | ✅ new ReentrantLock(true) |
| 条件变量 | 1个(wait/notify) | 多个(Condition) |
3.3 公平锁与非公平锁
java
// 非公平锁(默认,性能更好)
ReentrantLock unfairLock = new ReentrantLock();
// 公平锁(按等待顺序获取锁)
ReentrantLock fairLock = new ReentrantLock(true);4. ReentrantReadWriteLock
读写锁,适合读多写少的场景。
java
import java.util.concurrent.locks.*;
public class Cache {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
private Object data;
// 读操作,多个线程可以同时读
public Object read() {
readLock.lock();
try {
return data;
} finally {
readLock.unlock();
}
}
// 写操作,独占锁
public void write(Object newData) {
writeLock.lock();
try {
data = newData;
} finally {
writeLock.unlock();
}
}
}读写锁规则
| 操作 | 读锁 | 写锁 |
|---|---|---|
| 读-读 | ✅ 兼容 | - |
| 读-写 | ❌ 互斥 | ❌ 互斥 |
| 写-写 | - | ❌ 互斥 |
5. 线程间通信
5.1 wait/notify 机制
java
public class ProducerConsumer {
private final Object lock = new Object();
private int product = 0;
// 生产者
public void produce() throws InterruptedException {
synchronized (lock) {
while (product >= 10) {
lock.wait(); // 等待消费
}
product++;
System.out.println("生产:" + product);
lock.notifyAll(); // 通知消费者
}
}
// 消费者
public void consume() throws InterruptedException {
synchronized (lock) {
while (product <= 0) {
lock.wait(); // 等待生产
}
product--;
System.out.println("消费:" + product);
lock.notifyAll(); // 通知生产者
}
}
}⚠️ 注意:wait() 必须在 synchronized 块内调用,且使用 while 循环检查条件(防止虚假唤醒)。
5.2 Condition 条件变量
java
import java.util.concurrent.locks.*;
public class BoundedBuffer {
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final Object[] items = new Object[100];
private int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
notFull.await(); // 队列满,等待
}
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal(); // 通知消费者
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
notEmpty.await(); // 队列空,等待
}
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal(); // 通知生产者
return x;
} finally {
lock.unlock();
}
}
}5.3 wait/notify vs Condition
| 特性 | wait/notify | Condition |
|---|---|---|
| 条件个数 | 1个 | 多个 |
| 精准唤醒 | ❌ | ✅ |
| 配合使用 | synchronized | Lock |
| 等待方法 | wait() | await() |
| 唤醒方法 | notify()/notifyAll() | signal()/signalAll() |