Skip to content

线程同步

线程同步是并发编程的核心,用于控制多个线程对共享资源的访问,保证数据一致性。

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

特性synchronizedLock
释放锁自动释放手动调用 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/notifyCondition
条件个数1个多个
精准唤醒
配合使用synchronizedLock
等待方法wait()await()
唤醒方法notify()/notifyAll()signal()/signalAll()