Lock接口简介
Lock 接口是用于实现线程同步的一种机制。它提供了比传统的synchronized关键字更灵活和可扩展的方式来管理多个线程对共享资源的访问。
Lock 接口的主要目标是解决synchronized关键字的一些限制,例如无法中断正在等待锁的线程、不能尝试获取锁而立即放弃等待、不能在等待一段时间后获取锁等等。
Lock的特性
Lock接口中的常用方法
- void lock():获取锁,如果锁不可用,则阻塞当前线程。
- void lockInterruptibly():获取锁,但允许在等待过程中响应中断。
- boolean tryLock():尝试获取锁,如果锁可用则立即返回 true,否则返回 false,不会阻塞。
- boolean tryLock(long time, TimeUnit unit):尝试在指定的时间范围内获取锁,如果在指定时间内获取到锁则返回 true,否则返回 false。
- void unlock():释放锁,允许其他线程获取这个锁。
- Condition newCondition():创建一个与该锁关联的条件对象,用于线程之间的等待和通知。
Condition类的使用方式
只唤醒通过condition进入等待的线程,其他的线程不会被唤醒
Lock lock = new ReentrantLock(); // 创建锁
Condition condition = lock.newCondition(); // 通过锁来获取condition
public void conditionWait() throws InterruptedException {
lock.lock();
try {
condition.await(); // 让lock进入等待
} finally {
lock.unlock();
}
}
public void conditionSignal() throws InterruptedException {
lock.lock();
try {
condition.signal(); // 让lock被唤醒
} finally {
lock.unlock();
}
}
可重入锁与读写锁
Lock 接口的常见实现类包括 ReentrantLock 和 ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock。
ReentrantLock 是一个可重入的互斥锁,意味着同一个线程可以多次获得同一个锁。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
try {
lock.lock();
// 执行需要同步的操作
} finally {
lock.unlock();
}
}
}
ReentrantReadWriteLock 则提供了读写分离的锁机制,允许多个线程同时读取共享资源,但只有一个线程能够写入。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockExample {
public static void main(String[] args) {
ReadWriteLock lock = new ReentrantReadWriteLock();
SharedResource resource = new SharedResource();
// 创建多个读线程
for (int i = 0; i < 5; i++) {
new Thread(() -> {
resource.readData(lock.readLock());
}).start();
}
// 创建一个写线程
new Thread(() -> {
resource.writeData(lock.writeLock(), "New Data");
}).start();
}
}
class SharedResource {
private String data = "Initial Data";
public void readData(ReadWriteLock.ReadLock readLock) {
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + " is reading: " + data);
} finally {
readLock.unlock();
}
}
public void writeData(ReadWriteLock.WriteLock writeLock, String newData) {
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + " is writing...");
data = newData;
System.out.println(Thread.currentThread().getName() + " has written: " + data);
} finally {
writeLock.unlock();
}
}
}
多个读线程使用读锁来读取数据,而写线程使用写锁来修改数据。读锁可以被多个线程同时获取,从而实现读并发,而写锁只能被一个线程获取,保障写操作的原子性。