ReentrantReadWriteLock读写锁
import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.springframework.ui.context.Theme; public class ReentrantReadWriteLockTest { // 场景:现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁。在没有写操作的时候,多个线程同时读一个资源没有任何问题, // 所以应该允许多个线程同时读取共享资源;但是如果一个线程想去写这些共享资源,就不应该允许其他线程对该资源进行读和写的操作了 // 可重入读写锁 读写锁确保写锁的操作对读锁可见。 /** * 1;含义:他表示 两个锁,一个是读锁也叫共享锁,一个是写锁,也叫排他锁 * 2: 特性: 1.1: 锁可重入 1.2:读写分离 1.3:可降级 * 锁降级含义 :锁降级指的是写锁降级为读锁 * 因为读锁与读锁之间不互斥,如果是写锁与读锁或者是写锁与写锁就会互斥,所以由写锁变为读锁就降级了 * 如果当前线程拥有写锁,然后将其释放,最后再获取读锁,这种并不能称之为锁降级。 * 锁降级指的是把持住(当前拥有的)写锁,再获取到读锁,随后释放(先前有用的)写锁的过程。 * */ private static ReentrantReadWriteLock rw = new ReentrantReadWriteLock(); /** * volatile 保证了变量的可见性,被volatile 修饰的变量,如果有值变更,其他线程立马可见 * 注: volatile只能保证变量的可见性,不能保证对volatile变量操作的原子性 */ private volatile static Map<String,Object> map = new HashMap<String, Object>(); // 判断是否发生了 修改行为 private volatile static Boolean isUpdate =false; private volatile static int num=0; public static void main(String[] args) { // TODO Auto-generated method stub for(int i=0;i<=10;i++) { final int tempInt= i; new Thread(()-> { try { put(tempInt+"",tempInt+""); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } },String.valueOf(i) ).start();; } for(int i=0;i<=10;i++) { final int tempInt= i; new Thread( ()->{ try { get(tempInt+""); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }).start(); } for(int i=30;i<=40;i++) { // final int tempInt= i; new Thread( ()->{ processCacheData(); },i+"").start(); } } public static void put(String key ,Object value) throws InterruptedException { // 加写锁 rw.writeLock().lock(); System.out.println(Thread.currentThread().getName() + "正在写入" + key); // 休眠3 秒 TimeUnit.MILLISECONDS.sleep(300); map.put(key, value); System.out.println(Thread.currentThread().getName() +" 写入" + key); // 释放写锁 rw.writeLock().unlock(); } public static void get(String key ) throws InterruptedException { // 加读锁 rw.readLock().lock(); System.out.println(Thread.currentThread().getName() + " 正在读取" + key); TimeUnit.MILLISECONDS.sleep(300); Object result = map.get(key); System.out.println(Thread.currentThread().getName()+"\t 读取完成:"+result); rw.readLock().unlock(); } /** * 锁降级 */ public static void processCacheData() { //先获取读锁 rw.readLock().lock(); if(!isUpdate) { //在释放读锁 rw.readLock().unlock(); // 在获取写锁 rw.writeLock().lock(); // 进行写操作的时候在isUpdate 的最后值 try { if(!isUpdate) { num++; isUpdate=true; System.out.println(Thread.currentThread().getName() +"正在进行写操作,写入后值为" +num); //当前线程在获取 读锁 rw.readLock().lock(); System.out.println(Thread.currentThread().getName() +"我由写锁降低为读锁"); } } finally { System.out.println(Thread.currentThread().getName() +"我是读锁" + num); // 释放掉写锁 rw.writeLock().unlock(); } } try{ //模拟5秒的处理时间,并打印出当前值,在这个过程中cacheValid可能被其他线程修改,锁降级保证其他线程写锁被阻塞,数据不被改变 TimeUnit.MILLISECONDS.sleep(300); System.out.println(Thread.currentThread().getName() + ": " + num); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 当前线程保持的读取锁数量;如果当前线程从未保持过读取锁,则返回 0 if(rw.getReadHoldCount() > 0){ System.out.println("我释放掉了读锁" + Thread.currentThread().getName()); rw.readLock().unlock(); } } } }