Java多线程 ReadWriteLock读写锁的使用
1、ReadWriteLock 简介
(1)ReadWriteLock接口的实现类-ReentrantReadWriteLock读写锁两个锁,一个是读操作相关的锁也成为共享锁,一个是写操作相关的锁 也称为排他锁。通过分离读锁和写锁,其并发性比一般排他锁有了很大提升。
锁的特点:
1、多个读锁之间不互斥,
2、读锁与写锁互斥,
3、写锁与写锁互斥(只要出现写操作的过程就是互斥的。)
在没有线程Thread进行写入操作时,进行读取操作的多个Thread都可以获取读锁,而进行写入操作的Thread只有在获取写锁后才能进行写入操作。即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。
(2)ReentrantReadWriteLock的特性
特性 | 说明 |
---|---|
可重入性 | 该锁支持可重入,以读写线程为例:读线程在获取了读锁之后,能够再次获取读锁。而写线程在获取了写锁之后能够再次获取写锁也能够同时获取读锁 |
锁降级 | 写锁能够降级称为读锁,并遵循获取写锁、获取读锁再释放写锁的次序, |
公平性选择 | 支持非公平(默认)和公平的锁获取方式,吞吐量上来看还是非公平优于公平 |
(3)ReentrantReadWriteLock常见构造方法
ReentrantReadWriteLock(): 创建一个 ReentrantReadWriteLock()的实例
ReentrantReadWriteLock(boolean fair) :创建一个特定锁类型(公平锁/非公平锁)的ReentrantReadWriteLock的实例
2、实例:读者写者问题
读者—写者问题(Readers-Writers problem)也是一个经典的并发程序设计问题,是经常出现的一种同步问题。计算机系统中的数据(文件、记录)常被多个进程共享,但其中某些进程可能只要求读数据(称为读者Reader);另一些进程则要求修改数据(称为写者Writer)。就共享数据而言,Reader和Writer是两组并发进程共享一组数据区,要求:
(1)允许多个读者同时执行读操作;
(2)不允许读者、写者同时操作;
(3)不允许多个写者同时操作。
下面是ReentrantReadWriteLock的代码实现:
package chat7;
import java.util.Random;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockTest {
//内部类
class DataBase {
private Object data = null;// 共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(false);
public void get() {
rwl.readLock().lock();// 上读锁,其他线程只能读不能写
System.out.println("线程:" + Thread.currentThread().getName()
+ " 正在准备读取数据");
try {
Thread.sleep((long) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName()
+ "读到的数据为:" + data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
rwl.readLock().unlock(); // 释放读锁
}
}
public void put(Object data) {
rwl.writeLock().lock();// 上写锁,不允许其他线程读也不允许写
System.out.println(Thread.currentThread().getName()
+ " 正准备写进数据");
this.data = data;
System.out.println(Thread.currentThread().getName()
+ " 已经写进数据 " + data);
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
rwl.writeLock().unlock();// 释放写锁
}
}
public static void main(String[] args) {
final DataBase q = new DataBase();
for (int i = 0; i < 2; i++) { //创建两个读者线程
new Thread() {
public void run() {
while (true) {
q.get();
}
}
}.start();
}
for (int i = 0; i < 2; i++) { //创建两个写者进程
new Thread() {
public void run() {
while (true) {
q.put(new Random().nextInt(10000));
}
}
}.start();
}
}
}
}
3、总结
(1)ReentrantReadWriteLock的拥有三大特性:
可重入性,降级锁,公平性选择;
(2)锁的三大特点:
1、多个读锁之间不互斥,
2、读锁与写锁互斥,
3、写锁与写锁互斥(只要出现写操作的过程就是互斥的。)