public class ThreadTest2 {
public static void main(String[] args) {
LazySingle single = LazySingle.getSingle();
LazySingle single1 = LazySingle.getSingle();
System.out.println(single == single1);
}
}
- 当我们考虑多线程的时候 我们就会发现懒汉模式的单例模式在多线程中是一个多个线程去修改同一变量的操作 那么他必然会导致线程不安全 如何解决这点我在之前博客讲到过 就是 实现原子操作即可
- 而实现原子操作就是为其上锁 将 load change save 成原子操作
class LazySingle {
private LazySingle() {
}
private static LazySingle single;
public synchronized static LazySingle getSingle() {
if (single == null) {
single = new LazySingle();
}
return single;
}
}
-
但是我们发现上面写法将return语句也包含在原子操作里面 这样可以解决线程安全问题 但是 锁的粒度太大 将一些原本无关紧要的代码或者说本来可以并发执行的代码也变成原子操作 这样导致的粒度大就会降低这整段代码的并发执行能力降低了效率
-
所以我们对其再次进行优化
class LazySingle {
private LazySingle() {
}
private static LazySingle single;
public static LazySingle getSingle() {
synchronized (LazySingle.class) {
if (single == null) {
single = new LazySingle();
}
}
return single;
}
}
- 此时我们继续观察就会发现还有个特别重要的问题需要优化 如果有很多线程 后面一些线程就不是迸发执行 那样再让他们去尝试获取锁释放锁这样的操作就会降低他们的效率 所以我在加锁的外面再判断一次是否为空 这样 就可以保证后序线程的效率
class LazySingle {
private LazySingle() {
}
private static LazySingle single;
public static LazySingle getSingle() {
if (single == null) {
synchronized (LazySingle.class) {
if (single == null) {
single = new LazySingle();
}
}
}
return single;
}
}
最终版本
- 当我们在画时间线会发现 线程2一个线程会尝试去获取俩次single对象那么久有可能编译器对其进行优化 这样一旦优化就会出现内存可见性的安全问题 所以我们需要给single对象加上volatile去保证他的内存可见性
class LazySingle {
private LazySingle() {
}
private volatile static LazySingle single;
public static LazySingle getSingle() {
if (single == null) {
synchronized (LazySingle.class) {
if (single == null) {
single = new LazySingle();
}
}
}
给大家的福利
零基础入门
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
同时每个成长路线对应的板块都有配套的视频提供:
因篇幅有限,仅展示部分资料
网络安全面试题
绿盟护网行动
还有大家最喜欢的黑客技术
网络安全源码合集+工具包
所有资料共282G,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~
详情docs.qq.com/doc/DSlhRRFFyU2pVZGhS