1.读写锁

ReadWriteLock管理一组锁,一个是只读的锁,一个是写锁。 Java并发库中ReetrantReadWriteLock实现了ReadWriteLock接口并添加了可重入的特性
假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写(译者注:也就是说:读-读能共存,读-写不能共存,写-写不能共存)。这就需要一个读/写锁来解决这个问题。
对于lock的读写锁,可以通过new ReentrantReadWriteLock()获取到一个读写锁。所谓读写锁,便是多线程之间读不互斥,读写互斥。读写锁是一种自旋锁,如果当前没有读者,也没有写者,那么写者可以立刻获得锁,否则它必须自旋在那里,直到没有任何写者或读者。如果当前没有写者,那么读者可以立即获得该读写锁,否则读者必须自旋在那里,直到写者释放该锁
简单来说就是
独占锁(写锁):一次只能被一个线程占有 共享锁(读锁):该锁可以被多个线程占有!
先看一下没有锁的情况
package demo.ReadWriteLock;
import java.util.HashMap;
import java.util.Map;
public class ReadWriteLock {
public static void main(String[] args) {
Mycache mycache = new Mycache();
for (int i = 1; i <=5 ; i++) {
final int num = i;
new Thread(()->{
mycache.put(String.valueOf(num),num);
},String.valueOf(i)).start();
}
for (int i = 1; i <=5 ; i++) {
final int num = i;
new Thread(()->{
mycache.get(String.valueOf(num));
},String.valueOf(i)).start();
}
}
}
class Mycache{
private volatile Map<String,Object> map = new HashMap<>();
public void get(String key){
System.out.println(Thread.currentThread().getName()+"读取");
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取结果"+o);
}
public void put(String key,Object value){
System.out.println(Thread.currentThread().getName()+"写入");
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入完毕");
}
}
输出:
加锁
package demo.ReadWriteLock;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLocks {
public static void main(String[] args) {
MyCacheLock mycache = new MyCacheLock();
for (int i = 1; i <=5 ; i++) {
final int num = i;
new Thread(()->{
mycache.put(String.valueOf(num),num);
},String.valueOf(i)).start();
}
for (int i = 1; i <=5 ; i++) {
final int num = i;
new Thread(()->{
mycache.get(String.valueOf(num));
},String.valueOf(i)).start();
}
}
}
// 加锁操作: 读写锁
class MyCacheLock{
private volatile Map<String,Object> map = new HashMap<>();
// 读写锁
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 读 : 可以被多个线程同时读
public void get(String key){
// 这些锁一定要匹配,否则就可能导致死锁!
readWriteLock.readLock().lock(); // 多个线程同时持有
try {
System.out.println(Thread.currentThread().getName()+"读取" + key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取结果:"+o);
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
// 写 :应该是保证原子性 , 不应该被打扰
public void put(String key,Object value){
readWriteLock.writeLock().lock(); // 只能被一个线程占用
try {
System.out.println(Thread.currentThread().getName()+"写入" + key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入ok" );
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
}
输出:
总结
1.Java并发库中ReetrantReadWriteLock实现了ReadWriteLock接口并添加了可重入的特性
2.ReetrantReadWriteLock读写锁的实现中,读锁使用共享模式;写锁使用独占模式,换句话说,读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的
3.ReetrantReadWriteLock读写锁的实现中,需要注意的,当有读锁时,写锁就不能获得;而当有写锁时,除了获得写锁的这个线程可以获得读锁外,其他线程不能获得读锁
来源:CSDN
作者:去吧!小火龙
链接:https://blog.csdn.net/weixin_40307709/article/details/104678732