从synchronized到ReentrantLock_Java锁机制的演进与选择
1 引言
在Java并发编程中,锁机制是确保线程安全的关键。synchronized关键字和显式锁(如ReentrantLock)是两种常用的锁机制。本文将深入探讨这两种锁的工作原理、优缺点,并分析它们在不同场景下的最佳选择,帮助开发者做出明智的选择。
2 synchronized关键字详解
synchronized是Java中最基本的同步机制之一,它通过字节码指令实现,具有简单易用的特点。以下是synchronized的主要特点:
- 语法简单:可以直接应用于方法或代码块。
- 自动加锁与解锁:当线程进入同步代码块时自动加锁,退出时自动解锁。
- 可重入性:同一个线程可以多次获取同一把锁,不会导致死锁。
- 内置监视器锁:每个对象都有一个与之关联的监视器锁,synchronized关键字会隐式地使用这个锁。
public class SynchronizedExample {
private int count = 0;
// 同步方法
public synchronized void increment() {
count++;
}
// 同步代码块
public void decrement() {
synchronized (this) {
count--;
}
}
}
内部工作原理
- 字节码指令:编译器会将synchronized转换为字节码指令monitorenter和monitorexit。
- 锁升级:JVM引入了偏向锁、轻量级锁和重量级锁的概念,以优化锁的性能。初始状态下,锁处于偏向状态,如果只有一个线程访问,则直接偏向该线程;如果有多个线程竞争,则升级为轻量级锁;进一步竞争则升级为重量级锁。
3 ReentrantLock详解
ReentrantLock是java.util.concurrent.locks包中的显式锁,提供了比synchronized更灵活的锁控制。以下是ReentrantLock的主要特点:
- 显式加锁与解锁:需要手动调用lock()和unlock()方法。
- 公平锁与非公平锁:可以选择是否启用公平锁策略,默认是非公平锁。
- 条件变量支持:可以通过Condition对象实现更细粒度的线程同步。
- 超时机制:支持带超时的锁尝试(tryLock(long timeout, TimeUnit unit))。
- 中断响应:可以响应线程中断(lockInterruptibly())。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock(