zoukankan      html  css  js  c++  java
  • 8、ReadWriteLock读写锁

    引用学习(狂神说)

    为什么要使用ReadWriteLock锁呢?

    因为它是更加细粒度的操作,可以提升效率

    官方文档

    1、有两个锁,读锁和写锁

    2、可以做到:读可以有多个线程同时操作,写只能有一个线程操作

    3、在频繁的读写情况下,适合使用这个读写锁。

    4、并且只有一个实现类

    5、可以做到:先执行完所有写的线程,再执行读操作。

     

    没有加锁

    • 自定义缓存,多个线程进行读,多个线程进行写

    • 没有加锁的情况下:

    package com.zxh.add;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ReadWriteLockDemo {
        public static void main(String[] args) {
            MyCache cache = new MyCache();
    
            // 5个写线程
            for (int i = 1; i <= 5; i++) {
                final int temp = i;
                new Thread(()->{
                    cache.put(temp + "", temp + "");
                }, String.valueOf(i)).start();
            }
            // 5个读线程
            for (int i = 1; i <= 5; i++) {
                final int temp = i;
                new Thread(()->{
                    cache.read(temp + "");
                }, String.valueOf(i)).start();
            }
    
        }
    }
    /**
     * 自定义缓存
     */
    class MyCache{
    //    volatile,保证原子性,后面会讲
        private volatile Map<String, String> map = new HashMap<>();
    
        //
        public void put(String key, String value){
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入OK");
        }
    
        //
        public void read(String key){
            System.out.println(Thread.currentThread().getName() + "读取" + map.get(key));
            System.out.println(Thread.currentThread().getName() + "读取OK");
        }
    
    }

    存在问题

    1、在还没有写完的情况下,就插入了读操作;

    2、一个线程没有写完,被另一写线程插队了。

    3、还没有写入,读线程就读取了。

    加锁

    加了Lock锁的情况

    package com.zxh.add;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ReadWriteLockDemo {
        public static void main(String[] args) {
            MyCache2 cache = new MyCache2();
    
            // 5个写线程
            for (int i = 1; i <= 5; i++) {
                final int temp = i;
                new Thread(()->{
                    cache.put(temp + "", temp + "");
                }, String.valueOf(i)).start();
            }
            // 5个读线程
            for (int i = 1; i <= 5; i++) {
                final int temp = i;
                new Thread(()->{
                    cache.read(temp + "");
                }, String.valueOf(i)).start();
            }
    
        }
    }
    /**
     * 自定义缓存
     */
    class MyCache2{
        //    volatile,无法保证原子性,后面会讲,但是可以防止指令的重排
        private volatile Map<String, String> map = new HashMap<>();
    
        Lock lock = new ReentrantLock();
    
        //
        public void put(String key, String value){
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "写入" + key);
                map.put(key, value);
                System.out.println(Thread.currentThread().getName() + "写入OK");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
    
        }
    
        //
        public void read(String key){
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "读取" + key);
                map.get(key);
                System.out.println(Thread.currentThread().getName() + "读取OK");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
    }

    存在问题:

    1、没有存放,就进行了读取操作

    2、读取的时候,只能有一个线程操作,读完之后,其他线程才能继续,这样效率低,不满足一开始所说的,读可以被多个线程同时操作。

    加了ReadWriteLock锁的情况

    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class ReadWriteLockDemo {
        public static void main(String[] args) {
            MyCache3 cache = new MyCache3();
    
            // 5个写线程
            for (int i = 1; i <= 5; i++) {
                final int temp = i;
                new Thread(()->{
                    cache.put(temp + "", temp + "");
                }, String.valueOf(i)).start();
            }
            // 5个读线程
            for (int i = 1; i <= 5; i++) {
                final int temp = i;
                new Thread(()->{
                    cache.read(temp + "");
                }, String.valueOf(i)).start();
            }
    
        }
    }
    /**
     * 自定义缓存,加了ReadWriteLock读写锁
     */
    class MyCache3{
        //    volatile,保证原子性,后面会讲
        private volatile Map<String, String> map = new HashMap<>();
    
        ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); // 读写锁
    
        //
        public void put(String key, String 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(); //写解锁
            }
    
        }
    
        //
        public void read(String key){
            readWriteLock.readLock().lock();    // 读加锁
            try {
                System.out.println(Thread.currentThread().getName() + "读取" + map.get(key));
                System.out.println(Thread.currentThread().getName() + "读取OK");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                readWriteLock.readLock().unlock();  // 读解锁
            }
    
        }
    
    }

    可以看到非常完美,先执行完写的线程,再进行读操作;

    其次读的操作,是多个线程同时进行的,提高了效率;

    致力于记录学习过程中的笔记,希望大家有所帮助(*^▽^*)!
  • 相关阅读:
    Spring——注解代替XML配置文件,Spring与JUnit整合
    Spring——基本概念(IOC,DI思想),Spring配置文件(XML),属性注入,Spring与Web项目结合
    Struts——自定义拦截器
    Struts——OGNL表达式与Struts2结合
    Struts2——结果跳转方式配置(重定向,转发<默认>,重定向到方法,重定向到转发),获取servlet的内些API(request,servletcontext...),获取参数
    Struts2——基本使用与配置文件
    基于中间件的RBAC权限控制
    Django
    Django
    Django 中 admin 的执行流程
  • 原文地址:https://www.cnblogs.com/zxhbk/p/12960516.html
Copyright © 2011-2022 走看看