一、synchronized
关键字
1. 核心特性
- 隐式锁:自动获取和释放锁(进入同步代码块获取,退出时释放)。
- 可重入性:同一线程可多次获取同一锁(避免死锁)。
- 非公平锁:线程获取锁的顺序不保证公平性。
- 同步范围:通过代码块或方法实现同步。
2. 代码示例
(1) 同步代码块
java
复制
public class Counter {private int count = 0;private final Object lock = new Object();public void increment() {synchronized (lock) { // 锁对象可以是任意对象count++;}}public int getCount() {return count;}
}
(2) 同步方法
java
复制
public class Counter {private int count = 0;// 同步方法(锁对象是当前实例 this)public synchronized void increment() {count++;}// 静态同步方法(锁对象是类的 Class 对象)public static synchronized void staticMethod() {// 静态方法同步逻辑}
}
二、Lock
接口(ReentrantLock)
1. 核心特性
- 显式锁:需手动调用
lock()
和 unlock()
。 - 可中断:支持响应中断(
lockInterruptibly()
)。 - 公平锁:可配置为公平锁(按请求顺序分配锁)。
- 超时机制:尝试获取锁时可设置超时时间(
tryLock(long, TimeUnit)
)。 - 条件变量:通过
newCondition()
创建多个条件队列。
2. 代码示例
(1) 基本用法
java
复制
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Counter {private int count = 0;private final Lock lock = new ReentrantLock();public void increment() {lock.lock(); // 获取锁try {count++;} finally {lock.unlock(); // 必须释放锁(防止死锁)}}public int getCount() {return count;}
}
(2) 公平锁与条件变量
java
复制
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class BoundedBuffer<T> {private final T[] buffer;private int size = 0;private final Lock lock = new ReentrantLock(true); // 公平锁private final Condition notFull = lock.newCondition();private final Condition notEmpty = lock.newCondition();public BoundedBuffer(int capacity) {buffer = (T[]) new Object[capacity];}public void put(T item) throws InterruptedException {lock.lock();try {while (size == buffer.length) {notFull.await(); // 等待缓冲区不满}buffer[size++] = item;notEmpty.signal(); // 通知消费者可取数据} finally {lock.unlock();}}public T take() throws InterruptedException {lock.lock();try {while (size == 0) {notEmpty.await(); // 等待缓冲区不空}T item = buffer[--size];notFull.signal(); // 通知生产者可放数据return item;} finally {lock.unlock();}}
}
三、synchronized
与 Lock
对比
特性 | synchronized | Lock(ReentrantLock) |
---|
锁获取方式 | 隐式(自动获取/释放) | 显式(需手动调用 lock() 和 unlock() ) |
可中断性 | 不支持 | 支持(lockInterruptibly() ) |
公平性 | 仅非公平锁 | 可配置公平/非公平(构造函数参数) |
超时机制 | 不支持 | 支持(tryLock(long, TimeUnit) ) |
条件变量 | 仅一个(通过 wait()/notify() ) | 多个(通过 newCondition() ) |
性能 | 优化后接近 Lock | 高并发下更优(减少上下文切换) |
代码简洁性 | 简单(适合简单同步) | 灵活(适合复杂场景) |
四、使用场景与最佳实践
1. synchronized
适用场景
2. Lock
适用场景
五、常见问题与解决
1. 死锁问题
- 原因:多个线程互相持有对方所需锁,导致永久阻塞。
- 解决:
- 按固定顺序获取锁(避免循环等待)。
- 使用
tryLock()
尝试获取锁,超时则释放已持有锁。
2. 锁未释放
六、总结
-
synchronized
:简单易用,适合基础同步场景,但灵活性有限。 -
Lock
(ReentrantLock):功能丰富,适合复杂场景(如公平锁、多条件队列),但需手动管理锁。 - 选择原则:
- 优先使用
synchronized
(代码简洁)。 - 需要高级功能时选择
Lock
(如公平性、超时、多条件)。