不可不说的Java“锁”事(Java锁机制详解:不可不知的核心要点)
原创
一、Java锁机制概述
在Java并发编程中,锁是一种用于控制多个线程访问共享资源的机制。通过锁,我们可以保证同一时间只有一个线程可以访问共享资源,从而避免多线程并发致使的数据不一致和竞态条件问题。
二、Java锁的分类
Java中的锁重点分为以下几类:
- 内置锁(Intrinsic Lock)/监视器锁(Monitor Lock)
- 重入锁(ReentrantLock)
- 读写锁(ReadWriteLock)
- 条件锁(Condition)
- 开朗锁和悲观失望锁
- 偏向锁、轻量级锁和自旋锁
三、内置锁(Intrinsic Lock)/监视器锁(Monitor Lock)
内置锁是Java语言层面提供的锁机制,通过synchronized关键字实现。每个Java对象都可以作为锁。
public class SynchronizedExample {
public synchronized void synchronizedMethod() {
// 同步代码块
}
}
当线程访问synchronized方法或代码块时,线程会自动获取对象的内置锁,如果锁已被其他线程持有,则线程会等待锁释放。
四、重入锁(ReentrantLock)
重入锁是Java提供的一个显示锁,需要显式地加锁和解锁。ReentrantLock提供了比内置锁更充裕的功能,如可中断的锁获取、尝试非阻塞地获取锁、拥护公平锁等。
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void lockMethod() {
lock.lock();
try {
// 同步代码块
} finally {
lock.unlock();
}
}
}
五、读写锁(ReadWriteLock)
读写锁是一种允许多个线程同时读取共享资源,但在写入共享资源时需要互斥的锁。ReadWriteLock提供了读锁(共享锁)和写锁(排他锁)。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockExample {
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void readLockMethod() {
readWriteLock.readLock().lock();
try {
// 读取共享资源
} finally {
readWriteLock.readLock().unlock();
}
}
public void writeLockMethod() {
readWriteLock.writeLock().lock();
try {
// 写入共享资源
} finally {
readWriteLock.writeLock().unlock();
}
}
}
六、条件锁(Condition)
Condition是ReentrantLock的一个内部类,用于线程间的条件等待和通知。Condition提供了类似Object的wait()和notify()方法,但功能更强盛。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionExample {
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void conditionWait() throws InterruptedException {
lock.lock();
try {
condition.await();
} finally {
lock.unlock();
}
}
public void conditionSignal() {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
}
七、开朗锁和悲观失望锁
开朗锁和悲观失望锁是两种不同的锁策略。
- 开朗锁:假设没有冲突出现,在更新数据时检查是否有其他线程同时修改数据,如果有冲突,则放弃操作。
- 悲观失望锁:假设冲突一定会出现,在操作数据前先加锁,直到操作完成后再释放锁。
八、偏向锁、轻量级锁和自旋锁
Java虚拟机为了减成本时间锁的高效,引入了偏向锁、轻量级锁和自旋锁。
- 偏向锁:假设锁重点被一个线程持有,通过消除不必要的锁竞争来减成本时间性能。
- 轻量级锁:当没有竞争时,通过CAS操作避免使用重量级的操作系统互斥量。
- 自旋锁:当线程尝试获取锁时,不会立即阻塞,而是循环检查锁是否可用,以减少线程状态切换的开销。
九、总结
Java锁机制是并发编程中不可或缺的一部分。明白和掌握不同的锁类型和策略,能够帮助我们更好地解决多线程并发问题,减成本时间程序的性能和稳定性。在实际开发中,我们需要采取具体场景选择合适的锁,并注意避免死锁、饥饿和活锁等并发问题。