设计模式之单例模式读后思考(二)
上篇:我复习了6大原则, 睡觉前还想了一阵子, 我分析了一下, 想要牢记这些原则, 就必须动手写一些项目
学习地址: 左哥的blog
我记得我学习6大原则看了一个月, 这次这个单例模式 只看了4天, 有一点推动力感觉还是可以的
我自己的理解:
单例模式,原文: 指的是一个类在整个应用中, 有且只有一种状态.
本人理解: 类只有一个, 所有调用者拿到的都是这个类, 调用者的修改是阻塞的, 调用者的查询是非阻塞的,
单例模的应用场景基本都是在是可变共享
原文中有个让cpu飙升的测试单例的方法, TestSinglenton 这个测试方法 ,主要问题出在lock这个变量上, 在前面加上volatile这个变量, 保证可见性,
其实加了volatile cpu也会飙升, 但是结果可以及时打印出来
但是没加的话结果卡住,原因是什么,lock这个变量没有了可见性, 我推断lock.isLock()一直拿的是false, 所有的子线程一直没有获取到新的lock导致一直在循环
这时我就有个疑问了, 理论上在主线程我们改变lock的值, 但是这里显然, 子线程依然没有获取到我们想要的那个值, 难道说, lock之前的值依然没有被gc掉
我加了一小段代码检验的一番
while (true) { System.out.println("----"+lock.isLock()+"1------"); System.out.println("----"+lock.isLock()+"2------"); System.out.println("----"+lock.isLock()+"3------"); ..... }
结果,很震惊, 同一个线程下取到的lock值居然不一样, 并且 lock1总是初始值 lock3的数量>lock2, 这里感觉像 线程看着lock的值从true变成false
这5列代表5个线程
一个渐渐变化的过程, 等看完jvm再详细分析一波, 实际上是不是这样的呢?
终于, 我在java并发实战中找到了这个答案,
但是在实际的我还是发现的一个问题, 如果我没有打印这个lock,
①那么lock.isLock始终拿的是true, 一直在循环
②也有可能是由于数据竞争问题导致了线程阻塞, 这里到底是堵塞了,还是状态未更改
我使用jconsole 发现
从上面看结论是: ① 线程一直拿的是true 一直在循环
我也观察了内存使用状态
ps:这个工具是 jdk自带的工具, 路径:JAVA_HOME/bin/jconsole.exe
其中 新生代 eden 一直在增长 , 很多网站上搜索出来都是说是, 你new了对象的过程, 这里我就我观察到的结果来说 , 不是这样的
我的观点: 由于线程一直在循环, 生成了很多的代码缓存, 这些代码缓存中的一些对象或者基本类型数据的替换 都会重复的生成在 新生代,
我手动调用了一下gc, 其他区域没有变动, 新生代降了很多,其他区域不受影响
综上, 我得出一个结论:
多个线程读取同一个变量并且至少被一个以上的线程修改时, 如果该变量没有被volatile或同步关键词修饰或者读取的线程没有对该变量进行流操作 这里后来给其他同事测试发现, 可能只需要这个线程涉及到流的操作,就可以,具体原因以后发现继续更新, 那么读取线程始终无法获取到修改后的变量值
上面是我自己理解的有什么好的见解, 可以发到我的邮箱719285662@qq.com, 或者直接评价
好了单例模式告一段落,继续我的学习认证之路