Java多线程读写锁ReentrantReadWriteLock类详解
介绍
在多线程编程中,锁是保证数据安全的重要手段之一。常见的锁有synchronized和ReentrantLock,这两个锁都是互斥锁,当一个线程获得了锁,其他线程就无法获得锁,只能等待锁的释放。这种锁的特点是效率低下,只有一个线程能够访问共享资源,其他线程只能等待,不能并发访问,无法充分利用CPU资源。
读写锁是Java中提供的另一种锁机制,与互斥锁不同的是它允许共享锁,多个线程可以同时获得锁并发访问共享资源。读写锁是一种特殊的锁,它允许多个线程同时读共享资源,但只允许一个线程写共享资源。读写锁在读多写少的情况下能够显著提高程序的并发性能。
ReentrantReadWriteLock是Java提供的读写锁实现类之一,它实现了ReadWriteLock接口,支持可重入的读写锁。
ReentrantReadWriteLock的使用
使用ReentrantReadWriteLock,一般需要创建一个ReentrantReadWriteLock对象,然后通过该对象的readLock()和writeLock()方法分别获得读锁和写锁。
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
Lock readLock = lock.readLock();
Lock writeLock = lock.writeLock();
读锁和写锁的调用方式与互斥锁类似,不同的是读锁允许多个线程同时获得锁,写锁只允许一个线程获得锁。
readLock.lock();
//读共享资源
readLock.unlock();
writeLock.lock();
//写共享资源
writeLock.unlock();
示例1
下面我们通过一个简单的示例来演示ReentrantReadWriteLock的使用。
假设我们有一个共享的数据结构Map
首先,我们定义一个带有读写锁成员变量的类RWMap。
public class RWMap {
private final Map<String, String> map = new HashMap<>();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public String get(String key) {
lock.readLock().lock();
try {
return map.get(key);
} finally {
lock.readLock().unlock();
}
}
public void put(String key, String value) {
lock.writeLock().lock();
try {
map.put(key, value);
} finally {
lock.writeLock().unlock();
}
}
}
在get方法中,我们使用读锁来获取数据,因为多个线程可以同时读数据。在put方法中,我们使用写锁来更新数据,因为只有一个线程可以写入数据。
示例2
我们再来看一个更复杂一些的示例。假设我们有一个数字的计数器,该计数器有两个方法:increase()和decrease()。increase()方法将计数器加1,decrease()方法将计数器减1。我们需要实现一个程序,该程序从多个线程中调用这两个方法,并同步打印当前计数器值。在这个示例中,我们需要保证读写不冲突,即读操作和写操作不能同时进行。
我们可以使用ReentrantReadWriteLock实现这个程序。实现代码如下:
public class Counter {
private int count = 0;
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void increase() {
lock.writeLock().lock();
try {
count++;
} finally {
lock.writeLock().unlock();
}
}
public void decrease() {
lock.writeLock().lock();
try {
count--;
} finally {
lock.writeLock().unlock();
}
}
public int getCount() {
lock.readLock().lock();
try {
return count;
} finally {
lock.readLock().unlock();
}
}
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executor.execute(() -> {
for (int j = 0; j < 100; j++) {
counter.increase();
}
});
}
for (int i = 0; i < 100; i++) {
executor.execute(() -> {
for (int j = 0; j < 100; j++) {
counter.decrease();
}
});
}
executor.shutdown();
while (!executor.isTerminated()) { }
System.out.println("Count: " + counter.getCount());
}
}
在Counter类中,我们定义了一个计数器count和一个ReentrantReadWriteLock对象。increase()和decrease()方法使用了写锁,因为它们需要修改计数器的值。getCount()方法使用了读锁,因为它只需要读取计数器的值。
在Main类中,我们创建一个Counter对象和一个线程池,然后向线程池中提交100个加1和100个减1的任务。所有任务执行完毕后,输出计数器的值。
总结
ReentrantReadWriteLock是Java提供的一种读写锁实现,它允许多个线程并发地读取共享资源,但只允许一个线程写共享资源。使用ReentrantReadWriteLock可以大大提高程序的并发性能,尤其是在读多写少的情况下。在使用ReentrantReadWriteLock时需要注意的是要避免死锁情况的发生,正确地使用读锁和写锁。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程读写锁ReentrantReadWriteLock类详解 - Python技术站