ReadWriteLock |
读写锁
1、简介
JDK1.5引入的读写锁ReadWriteLock相对于ReentrantLock来说,锁的粒度更小。ReadWriteLock把锁分为读锁和写锁
- 写锁,又称排它锁,独占锁。顾名思义,每次只能被一条线程所持有,其他线程不能在读取或修改共享资源了。
- 读锁,又称共享锁。读锁可以同时被多个线程持有,获得读锁的线程,只能读取共享资源而不能修改。多个读操作同时进行,其实并没有线程安全问题,此时可以使用读锁,用来提高程序效率。
2、ReadWriteLock的实现类ReentrantReadWriteLock
- 支持公平模式和非公平模式,默认为非公平模式
- 支持重入,读锁可以重入获取读锁,写锁可以重入获取写锁,写锁可以获取读锁,读锁不可以获取写锁。
- 允许一个线程先获得写锁,然后获取读锁,通过释放写锁的方式降级。但是,从读锁升级到写锁是不被允许的。
- 读锁和写锁都支持锁获取期间的中断
- 写锁支持Condition ,读锁不支持
3、代码示例
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyMap map = new MyMap();
new Thread(()->{ map.put("one",""); }).start();
new Thread(()->{ map.put("two",""); }).start();
new Thread(()->{ map.get("one"); }).start();
new Thread(()->{ map.get("two"); }).start();
}
}
class MyMap{
private volatile HashMap<String, String> map=new HashMap<>();
private final ReadWriteLock lock=new ReentrantReadWriteLock();
//写
public void put(String str1,String str2){
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"开始写");
TimeUnit.SECONDS.sleep(2);
map.put(str1,str2);
System.out.println(Thread.currentThread().getName()+"写完");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
//读
public void get(String str1){
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"开始读");
TimeUnit.SECONDS.sleep(2);
String s = map.get(str1);
System.out.println(Thread.currentThread().getName()+"读完");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
}
}
从运行结果可以看到,线程0,获取率写锁,线程1在线程0释放了写锁之后才获得锁,所以写入操作每次只有一条线程操作,而线程2和线程3都获得了读锁,所以读可以有多条线程。