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