JUC----04
1.1 读写问题
ReadWriteLockUnsafeDemo:
public class ReadWriteLockUnsafeDemo {
    // TODO: 2020/7/25  模拟多线程对公共资源类的读和写操作,没有加锁,不安全
    static class Cache {
        private HashMap<String, Object> cache = new HashMap<>();
        //写入缓存
        public void put(String key, Object val) {
            try {
                System.out.println(Thread.currentThread().getName() + " 开始写入");
                cache.put(key, val);
                System.out.println(Thread.currentThread().getName() + " 写入完成");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
        }
        //从缓存中读取数据
        public void get(String key) {
            try {
                System.out.println(Thread.currentThread().getName() + " 开始读取");
                Object obj = cache.get(key);
                System.out.println(Thread.currentThread().getName() + " 读取完成 : " + obj);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }
        }
    }
    public static void main(String[] args) {
        Cache cache = new Cache();
        for (int i = 0; i < 5; ++i) {
            final int tempI = i;
            new Thread(() -> {
                cache.put(String.valueOf(tempI), tempI);
            }).start();
        }
        for (int i = 0; i < 5; ++i) {
            final int tempI = i;
            new Thread(() -> {
                cache.get(String.valueOf(tempI));
            }).start();
        }
    }
}
运行结果:
Thread-0 开始写入
Thread-1 开始写入
Thread-1 写入完成
Thread-0 写入完成
Thread-2 开始写入
Thread-2 写入完成
Thread-3 开始写入
Thread-3 写入完成
Thread-5 开始读取
Thread-5 读取完成 : 0
Thread-4 开始写入
Thread-4 写入完成
Thread-6 开始读取
Thread-6 读取完成 : 1
Thread-7 开始读取
Thread-7 读取完成 : 2
Thread-8 开始读取
Thread-9 开始读取
Thread-9 读取完成 : 4
Thread-8 读取完成 : 3
首先我们可以发现在写操作的时候线程发生的争抢。
ReadWriteLockDemo:
public class ReadWriteLockDemo {
    /**
     * * 读-读 : 无锁
     * * 读-写 : 锁
     * * 写-写 : 锁
     */
    //模拟缓存被读和被写
    static class Cache {
        private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        private HashMap<String, Object> cache = new HashMap<>();
        //写入缓存
        public void put(String key, Object val) {
            /**
             * 加写锁
             */
            readWriteLock.writeLock().lock();
            try {
                System.out.println(Thread.currentThread().getName() + " 开始写入");
                cache.put(key, val);
                System.out.println(Thread.currentThread().getName() + " 写入完成");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                readWriteLock.writeLock().unlock();
            }
        }
        //从缓存中读取数据
        public void get(String key) {
            /**
             * 加读锁
             */
            readWriteLock.readLock().lock();
            try {
                System.out.println(Thread.currentThread().getName() + " 开始读取");
                Object obj = cache.get(key);
                System.out.println(Thread.currentThread().getName() + " 读取完成 : " + obj);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                readWriteLock.readLock().unlock();
            }
        }
    }
    public static void main(String[] args) {
        Cache cache = new Cache();
        for (int i = 0; i < 5; ++i) {
          final int tempI = i;
            new Thread(() -> {
                cache.put(String.valueOf(tempI), tempI);
            }).start();
        }
        for (int i = 0; i < 5; ++i) {
            final int tempI = i;
            new Thread(() -> {
                cache.get(String.valueOf(tempI));
            }).start();
        }
    }
}
运行结果:
Thread-0 开始写入
Thread-0 写入完成
Thread-1 开始写入
Thread-1 写入完成
Thread-2 开始写入
Thread-2 写入完成
Thread-3 开始写入
Thread-3 写入完成
Thread-4 开始写入
Thread-4 写入完成
Thread-5 开始读取
Thread-5 读取完成 : 0
Thread-6 开始读取
Thread-6 读取完成 : 1
Thread-7 开始读取
Thread-7 读取完成 : 2
Thread-8 开始读取
Thread-8 读取完成 : 3
Thread-9 开始读取
Thread-9 读取完成 : 4
可以看到写操作保证了原子性,读操作不加锁任意读。
这里的读操作不加锁,可能有些人会说既然不加锁,那为什么这一步要获取读锁?

这里的加锁是为了和读操作分离开来,保证上面的读锁释放完后(读操作做完了)再进行读,而各个读线程之间是不加锁的。
java这部分东西都藏在源码里了,我个人认为上面的代码严格来说属于写优先算法。写写互斥,写优先。
熟悉操作系统的都知道读写问题一般分三种:
- 读优先
 - 写优先
 - 读写公平
 
JUC----04的更多相关文章
- Java多线程系列--“JUC集合”04之 ConcurrentHashMap
		
概要 本章是JUC系列的ConcurrentHashMap篇.内容包括:ConcurrentHashMap介绍ConcurrentHashMap原理和数据结构ConcurrentHashMap函数列表 ...
 - Java多线程系列--“JUC锁”04之 公平锁(二)
		
概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...
 - Java多线程系列--“JUC原子类”04之 AtomicReference原子类
		
概要 本章对AtomicReference引用类型的原子类进行介绍.内容包括:AtomicReference介绍和函数列表AtomicReference源码分析(基于JDK1.7.0_40)Atomi ...
 - Java多线程系列--“JUC线程池”04之 线程池原理(三)
		
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基 ...
 - java多线程系类:JUC线程池:04之线程池原理(三)(转)
		
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--"基础篇& ...
 - java多线程系类:JUC原子类:04之AtomicReference原子类
		
概要 本章对AtomicReference引用类型的原子类进行介绍.内容包括:AtomicReference介绍和函数列表AtomicReference源码分析(基于JDK1.7.0_40)Atomi ...
 - Java多线程系列  JUC线程池04   线程池原理解析(三)
		
转载 http://www.cnblogs.com/skywang12345/p/3509954.html https://blog.csdn.net/qq_22929803/article/det ...
 - JUC 并发编程--04  常用的辅助类CountDownLatch  ,  CyclicBarrier ,  Semaphore ,  读写锁 , 阻塞队列,CompletableFuture(异步回调)
		
CountDownLatch 相当于一个减法计数器, 构造方法指定一个数字,比如6, 一个线程执行一次,这个数字减1, 当变为0 的时候, await()方法,才开始往下执行,, 看这个例子 Cycl ...
 - Java多线程系列--“JUC锁”03之 公平锁(一)
		
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
 - Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例
		
概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...
 
随机推荐
- windows下nginx问题:[crit] 796#7096: *1 GetFileAttributesEx() "F: ginx-1.12.2\html\dist" failed (123: The filename, directory name, or volume label syntax is incorrect), client: 127.0.0.1, server: localho
			
错误信息: 2019/09/09 13:54:37 [crit] 796#7096: *1 GetFileAttributesEx() "F: ginx-1.12.2\html\dist&q ...
 - Mybatis(四)多表操作
			
数据库如下: 一.创建数据库所对应的bean类 public class User { private Integer uId; private String username; private St ...
 - 关于简单的数据双向绑定原理,defineProperty 和Proxy演示
			
双向绑定,也就是说js中的数据传到页面,页面中的内容到js,实现同步更新,简单的演示可以直接复制下放HTML代码运行. 在这个例子中,我们使用defineProperty ,Object.define ...
 - 前端学习(十二):CSS排版
			
进击のpython ***** 前端学习--CSS排版 本节主要介绍网页排版中主要格式化元素属性 帮助开发者把css技术与网页排版紧密联系到一起,来更好的实现网页设计效果 字体属性 字体 在日常工作中 ...
 - laravel 迁移文件中修改含有enum字段的表报错解决方法
			
解决方法: 在迁移文件中up方法最上方加上下面这一行代码即可: Schema::getConnection()->getDoctrineSchemaManager()->getDataba ...
 - link小图标以及表格的用法基础
			
一.网页小图标的实现 实例: 实现方式: 效果: 二.表格基础 1.表格的组合标签 常用: table tr td caption ①table属性 border 边框 width 宽度 默认按照 ...
 - 2016A06寒假作业 全排列
			
又是一个全排列哈, 注意注意,这个题不是十三个数字都需要,但原理是一样的 一开始把for的边界写错了(每次其实应该从k开始,还没看出来orz) #include <iostream> #i ...
 - 巩固复习(Django最基础的部分_具体查看官方文档)
			
Django学习路1 1.脚本不能随便运行,没准 linux 运行完就上不去了 2.pip 在 linux 上 写 pip3 同理 python 写为 python3 3.在 pycharm 上安装库 ...
 - PHP array_diff() 函数
			
实例 比较两个数组的值,并返回差集: <?php $a1=array("a"=>"red","b"=>"gree ...
 - PHP is_int() 、is_integer()、is_long() 函数
			
is_int() 函数用于检测变量是否是整数.高佣联盟 www.cgewang.com 注意: 若想测试一个变量是否是数字或数字字符串(如表单输入,它们通常为字符串),必须使用 is_numeric( ...