java实现ReadWriteLock读写锁的示例
作者:草履虫·
读写锁基本概念
ReadWriteLock是Java并发包中的一个接口,它定义了两种锁:读锁(Read Lock)和写锁(Write Lock),真正的实现类是ReentrantReadWriteLock。读锁允许多个线程同时读取共享资源,而写锁则要求独占资源,即当一个线程持有写锁时,其他线程不能获取读锁或写锁。
读写锁的作用
在进行共享资源的并发访问时,不论是使用synchronized还是使用重入锁ReentrantLock,一次都只允许一个线程访问共享资源,但是很多时候我们只是要读取共享资源,并不修改共享资源,多个线程同时读取共享资源并不会产生不一致问题,而且还能提高并发效率,对共享资源修改时就只让一个线程进入,又保证数据的一致性,这就是读写锁ReadWriteLock诞生的原因。读写锁分离是一种常见的锁思想。例如在一些数据库内,利用读锁让多个事务可以同时读某行数据,并且数据不会被修改,利用写锁保证只有一个事务可以修改某行数据,并且不会被其它事务读取到脏数据。
写锁:也叫作排他锁,如果数据有加写锁,就只有持有写锁的线程才能对数据进行操作,数据加持着写锁时,其他线程不能加写锁,也不能施加读锁。
读锁:也叫作共享锁,多个线程可以对同一个数据添加多个读锁,数据被加上读锁后就不能再被加上写锁。
读写锁的使用
使用ReadWriteLock实现读写控制示例:
import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReentrantReadWriteLock; public class RWLock { public static final CountDownLatch countDownLatch = new CountDownLatch(10); public static final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); //获取读锁 public static final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock(); //获取写锁 public static final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock(); public static void main(String[] args) throws InterruptedException { long start = System.currentTimeMillis(); //8个线程模拟读操作 for (int i = 0; i < 8; i++) { new Thread(() -> { readLock.lock(); try { Thread.sleep(1000); // 模拟读操作 countDownLatch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } finally { readLock.unlock(); } }).start(); } //2个线程模拟写操作 for (int i = 0; i < 2; i++) { new Thread(() -> { writeLock.lock(); try { Thread.sleep(2000); // 模拟写操作 countDownLatch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } finally { writeLock.unlock(); } }).start(); } //等待所有操作完成 countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println("任务完成,耗时:" + (end - start)); } } //任务完成,耗时:3081
使用ReentrantLock实现读写控制示例:
import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReentrantLock; public class RWLock { public static final CountDownLatch countDownLatch = new CountDownLatch(10); public static final ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) throws InterruptedException { long start = System.currentTimeMillis(); for (int i = 0; i < 10; i++) { new Thread(() -> { lock.lock(); try { Thread.sleep(1000); // 模拟读操作 countDownLatch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }).start(); } //等待所有操作完成 countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println("任务完成,耗时:" + (end - start)); } } //任务完成,耗时:10155
以上两个示例中,使用ReadWriteLock实现的读写控制任务总耗时3秒左右,而使用ReentrantLock的实现的读写控制任务总耗时10秒左右,在这个例子中ReadWriteLock比ReentrantLock快了3倍多,这是否就意味着ReadWriteLock的性能就一定比ReentrantLock好呢?其实不是的,ReadWriteLock适用于读多写少的场景,如上面例子中使用了8个线程模拟读操作,2个线程模拟写操作就是读多写少的场景,在写操作密集的场景下ReadWriteLock的复杂性使它具有更大的锁开销。应该在不同的场景下选择合适的锁。
到此这篇关于java实现ReadWriteLock读写锁的示例的文章就介绍到这了,更多相关java ReadWriteLock读写锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!