Java中有哪些锁?

分类: 365提款超过7天 时间: 2025-07-11 21:24:08 作者: admin 阅读: 9595 点赞: 951
Java中有哪些锁?

1. synchronized 锁

作用:

synchronized 是 Java 最基础的锁机制,用于实现方法或代码块的同步,保证多线程环境下的原子性、可见性和有序性。

使用方式:

对象锁:修饰实例方法或代码块(锁对象为当前实例 this)。

public synchronized void method() { ... } // 实例方法锁

public void method() {

synchronized (this) { ... } // 代码块锁(对象锁)

}

类锁:修饰静态方法或代码块(锁对象为类的 Class 对象)。

public static synchronized void staticMethod() { ... } // 静态方法锁

public void method() {

synchronized (MyClass.class) { ... } // 代码块锁(类锁)

}

特点:

隐式锁:自动获取和释放锁,无需手动管理。

可重入:线程可重复获取同一把锁。

非公平锁:默认抢占式获取锁,不保证等待时间长的线程优先获取。

适用场景:

简单同步需求,如单例模式的双重检查锁。

2. ReentrantLock(可重入锁)

作用:

ReentrantLock 是 java.util.concurrent.locks 包下的显式锁,提供比 synchronized 更灵活的锁控制。

使用方式:

ReentrantLock lock = new ReentrantLock();

public void method() {

lock.lock(); // 手动加锁

try {

// 临界区代码

} finally {

lock.unlock(); // 必须手动释放

}

}

核心功能:

尝试非阻塞获取锁:tryLock()。

超时获取锁:tryLock(long timeout, TimeUnit unit)。

公平性选择:构造函数传入 true 实现公平锁(按等待顺序分配锁)。

条件变量:配合 Condition 实现线程间协调(如生产者-消费者模型)。

优缺点:

优点:灵活,支持中断、超时、公平锁。

缺点:需手动释放锁,编码不当易导致死锁。

适用场景:

需要复杂同步控制的场景,如多条件等待、锁超时处理。

3. ReadWriteLock(读写锁)

作用:

允许多个线程同时读,但写线程独占资源,适用于读多写少的场景。

实现类:ReentrantReadWriteLock。

使用方式:

ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();

ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();

public void readData() {

readLock.lock();

try { ... } finally { readLock.unlock(); }

}

public void writeData() {

writeLock.lock();

try { ... } finally { writeLock.unlock(); }

}

特点:

读共享:多个读线程可同时访问。

写独占:写线程获取锁时,禁止其他读/写操作。

锁降级:写锁可降级为读锁(反之不可)。

适用场景:

缓存系统、频繁读取但偶尔更新的数据结构。

4. StampedLock(Java 8+)

作用:

提供更灵活的读写锁控制,支持乐观读、悲观读、写锁三种模式,性能优于 ReadWriteLock。

使用方式:

StampedLock stampedLock = new StampedLock();

// 乐观读(无锁)

long stamp = stampedLock.tryOptimisticRead();

if (!stampedLock.validate(stamp)) { // 检查是否发生写操作

stamp = stampedLock.readLock(); // 退化为悲观读

try { ... } finally { stampedLock.unlockRead(stamp); }

}

// 写锁

long writeStamp = stampedLock.writeLock();

try { ... } finally { stampedLock.unlockWrite(writeStamp); }

特点:

乐观读:假设没有写操作,通过 validate() 验证。

锁转换:支持读锁与写锁的转换(如 tryConvertToWriteLock())。

适用场景:

读多写少且对性能要求极高的场景,但需谨慎处理锁转换逻辑。

5. 显式锁 vs 隐式锁

维度显式锁(如 ReentrantLock)隐式锁(synchronized)锁获取方式手动调用 lock() 和 unlock()自动获取和释放灵活性支持超时、中断、公平锁、条件变量仅支持非公平锁,无超时或中断机制性能高并发场景下更优优化后性能接近显式锁(如锁升级机制)代码复杂度需手动管理,易出错自动管理,代码简洁

6. 锁优化策略(JVM 对 synchronized 的优化)

偏向锁:

假设只有一个线程访问同步块,通过标记线程 ID 避免 CAS 操作。

适用场景:单线程重复访问同步代码。

轻量级锁:

当多线程竞争时,通过 CAS 自旋尝试获取锁(避免阻塞)。

适用场景:低竞争、同步块执行时间短。

重量级锁:

竞争激烈时,线程进入阻塞状态,依赖操作系统的互斥量(Mutex)管理。

适用场景:高竞争、同步块执行时间长。

锁升级流程:

无锁 → 偏向锁 → 轻量级锁 → 重量级锁

7. 条件锁(Condition)

作用:

配合显式锁(如 ReentrantLock)使用,实现线程的等待/唤醒机制,类似 Object.wait() 和 Object.notify(),但更灵活。

使用方式:

ReentrantLock lock = new ReentrantLock();

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(); }

}

适用场景:

生产者-消费者模型、多条件线程协调。

8. 分布式锁

作用:

在分布式系统中协调多节点对共享资源的访问,防止并发冲突。

实现方式:

Redis:通过 SETNX(或 RedLock 算法)实现。

// 使用 Redisson 客户端

RLock lock = redisson.getLock("myLock");

lock.lock();

try { ... } finally { lock.unlock(); }

ZooKeeper:通过临时有序节点实现。

数据库:利用唯一索引或乐观锁(版本号)。

核心挑战:

死锁预防:设置锁超时时间。

容错性:避免单点故障(如 Redis 集群)。

总结

锁类型核心特点适用场景synchronized简单、自动管理,支持锁升级优化简单同步需求ReentrantLock灵活,支持超时、公平锁、条件变量复杂同步控制(如多条件等待)ReadWriteLock读写分离,读多写少场景性能更优缓存、频繁读的数据结构StampedLock高性能,支持乐观读极高并发读场景分布式锁跨进程、跨节点协调分布式系统资源共享

选择建议:

优先使用 synchronized(简单场景)。

需要灵活控制时选 ReentrantLock。

读多写少用 ReadWriteLock 或 StampedLock。

分布式环境用 Redis/ZooKeeper 实现分布式锁。

相关推荐