①ReadWriteLock同Lock一样也是一个接口,
提供了readLock和writeLock两种锁的操作机制,一个是读锁,一个是写锁。
读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的(排他的)。每次只能有一个写线程,但是可以有多个线程并发地读数据。
所有读写锁的实现必须确保写操作对读操作的内存影响。
换句话说,一个获得了读锁的线程必须能看到前一个释放的写锁所更新的内容。
理论上,读写锁比互斥锁允许对于共享数据更大程度的并发。
与互斥锁相比,读写锁是否能够提高性能取决于读写数据的频率、读取和写入操作的持续时间、以及读线程和写线程之间的竞争。
②使用场景
假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。
例如,最初填充有数据,然后很少修改的集合,同时频繁搜索(例如某种目录)是使用读写锁的理想候选项。
在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写。
这就需要一个读/写锁来解决这个问题。
③互斥原则:.
读—读能共存
读—写不能共存
写—写不能共。
代码示例
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ThreadTest {
public static void main(String[] args) {
ReadWriteLockTest rwlt = new ReadWriteLockTest();
//开启10条线程读
for (int i =1; i <=10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
rwlt.get();//读取共享资源
}
},"A").start();
}
//开启一条线程来写
new Thread(new Runnable() {
@Override
public void run() {
rwlt.set(12);
}
},"B").start();
}
}
class ReadWriteLockTest{
//定义一个线程间共享的数据
private int num=0;
//用到读写锁
ReadWriteLock rwl=new ReentrantReadWriteLock();
//定义两个方法
public void get(){
rwl.readLock().lock();//使用读锁
try {
System.out.println(Thread.currentThread().getName()+":"+num);
}finally {
rwl.readLock().unlock();//释放读锁
}
}
public void set(int num){
rwl.writeLock().lock();//使用写锁
try {
this.num=num;
}finally {
rwl.writeLock().unlock();//释放写锁
}
}
}