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();
             }
         }
     }
     
     
     

}

 

posted @ 2020-03-15 22:29  石shi  阅读(140)  评论(0编辑  收藏  举报