问:聊聊JAVA中的共享锁和独占锁?
在Java并发包java.util.concurrent
中,ReentrantLock
是独占锁的一个典型实现,而ReentrantReadWriteLock
则提供了共享锁和独占锁的实现。本文将介绍一下这两种锁。
独占锁(Exclusive Lock)
独占锁模式下,每次只能有一个线程持有锁。这意味着当一个线程持有锁时,其他线程必须等待该线程释放锁后才能获取锁。ReentrantLock
就是以独占方式实现的互斥锁。
代码示例:
import java.util.concurrent.locks.ReentrantLock;
public class ExclusiveLockExample {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock(); // 获取独占锁
try {
count++;
} finally {
lock.unlock(); // 释放独占锁
}
}
public int getCount() {
return count;
}
public static void main(String[] args) {
ExclusiveLockExample example = new ExclusiveLockExample();
// 创建多个线程同时执行increment操作
for (int i = 0; i < 10; i++) {
new Thread(example::increment).start();
}
// 等待所有线程执行完毕
// (实际应用中可使用更合适的同步机制,如CountDownLatch)
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + example.getCount());
}
}
在上面的代码中,increment
方法使用ReentrantLock
来确保在同一时间只有一个线程能够修改count
变量。
共享锁(Shared Lock)
共享锁允许多个线程同时获取锁,并发访问共享资源。ReentrantReadWriteLock
中的读锁(ReadLock
)就是共享锁的一个实现。
代码示例:
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class SharedLockExample {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
private int count = 0;
public void readCount() {
readLock.lock(); // 获取共享锁
try {
System.out.println("Read count: " + count);
} finally {
readLock.unlock(); // 释放共享锁
}
}
public void writeCount(int newValue) {
writeLock.lock(); // 获取独占锁
try {
count = newValue;
} finally {
writeLock.unlock(); // 释放独占锁
}
}
public static void main(String[] args) {
SharedLockExample example = new SharedLockExample();
// 创建多个读线程
for (int i = 0; i < 5; i++) {
new Thread(example::readCount).start();
}
// 创建一个写线程
new Thread(() -> example.writeCount(42)).start();
// 等待所有线程执行完毕
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上面的代码中,readCount
方法使用读锁(共享锁)来允许多个线程同时读取count
变量,而writeCount
方法使用写锁(独占锁)来确保在写操作期间没有其他线程读取或写入count
变量。
总结
特性 | 独占锁 (ReentrantLock) | 共享锁 (ReentrantReadWriteLock.ReadLock) |
---|---|---|
锁类型 | 互斥锁,每次只能有一个线程持有 | 允许多个线程同时持有 |
并发性 | 低,因为只有一个线程能访问资源 | 高,因为多个读线程能同时访问资源 |
使用场景 | 需要确保数据一致性的写操作 | 允许多个读操作并发执行,但写操作需要独占 |
JAVA类 | ReentrantLock | ReentrantReadWriteLock.ReadLock |
锁获取 | lock() 方法 | readLock().lock() 方法 |
锁释放 | unlock() 方法 | readLock().unlock() 方法 |
独占锁和共享锁在Java并发编程中各有其适用场景。独占锁适用于需要严格保证数据一致性的写操作,而共享锁则适用于允许多个读操作并发执行的场景。在实际应用中,应根据具体需求选择合适的锁类型。