JVM中的锁机制有哪些?如何选择合适的锁?

详细说明JVM中的各种锁机制,包括synchronized、ReentrantLock、ReadWriteLock等,以及锁的选择策略

参考答案

JVM提供了多种锁机制来保证多线程程序的正确性,每种锁都有其适用场景:

  1. synchronized关键字

基本用法

public class SynchronizedExample {
// 实例方法同步
public synchronized void method1() {
// 临界区代码
}

// 静态方法同步
public static synchronized void method2() {
// 临界区代码
}

// 代码块同步
public void method3() {
synchronized (this) {
// 临界区代码
}
}
}

实现原理

  • 对象头:Mark Word存储锁信息
  • 监视器:每个对象关联一个监视器
  • 锁升级:偏向锁→轻量级锁→重量级锁

特点

  • 自动加锁和释放
  • 可重入
  • 非公平锁
  • 性能相对较低
  1. ReentrantLock

基本用法

public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();

public void method() {
lock.lock();
try {
// 临界区代码
} finally {
lock.unlock();
}
}
}

高级特性

public class AdvancedLockExample {
private final ReentrantLock lock = new ReentrantLock(true); // 公平锁
private final Condition condition = lock.newCondition();

public void await() throws InterruptedException {
lock.lock();
try {
condition.await();
} finally {
lock.unlock();
}
}

public void signal() {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
}

特点

  • 手动加锁和释放
  • 支持公平锁和非公平锁
  • 支持条件变量
  • 性能相对较高
  1. ReadWriteLock

基本用法

public class ReadWriteLockExample {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();

private Map<String, Object> cache = new HashMap<>();

public Object get(String key) {
readLock.lock();
try {
return cache.get(key);
} finally {
readLock.unlock();
}
}

public void put(String key, Object value) {
writeLock.lock();
try {
cache.put(key, value);
} finally {
writeLock.unlock();
}
}
}

特点

  • 读锁共享,写锁独占
  • 适合读多写少的场景
  • 提高并发性能
  • 避免写饥饿
  1. StampedLock

基本用法

public class StampedLockExample {
private final StampedLock lock = new StampedLock();
private double x, y;

public void move(double deltaX, double deltaY) {
long stamp = lock.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
lock.unlockWrite(stamp);
}
}

public double distanceFromOrigin() {
long stamp = lock.tryOptimisticRead();
double currentX = x, currentY = y;
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try {
currentX = x;
currentY = y;
} finally {
lock.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
}

特点

  • 支持乐观读锁
  • 性能最高
  • 不支持条件变量
  • 适合读多写少的场景
  1. 锁的选择策略

性能考虑

  • 低竞争:synchronized
  • 中等竞争:ReentrantLock
  • 高竞争:StampedLock

功能需求

  • 需要条件变量:ReentrantLock
  • 读多写少:ReadWriteLock或StampedLock
  • 简单同步:synchronized

公平性要求

  • 公平锁:ReentrantLock(true)
  • 非公平锁:synchronized或ReentrantLock(false)
  1. 锁的性能优化

减少锁竞争

public class OptimizedLockExample {
// 使用分段锁减少竞争
private final Lock[] locks = new Lock[16];
private final Map<String, Object>[] maps = new Map[16];

public OptimizedLockExample() {
for (int i = 0; i < 16; i++) {
locks[i] = new ReentrantLock();
maps[i] = new HashMap<>();
}
}

public Object get(String key) {
int index = key.hashCode() % 16;
locks[index].lock();
try {
return maps[index].get(key);
} finally {
locks[index].unlock();
}
}
}

锁的粒度控制

  • 细粒度锁:减少竞争但增加复杂度
  • 粗粒度锁:简单但可能影响性能
  • 根据实际场景选择合适的粒度

评论区 (0)

暂无评论,来发表第一条评论吧!