首页
关于
友链
Search
1
wlop 4K 壁纸 4k8k 动态 壁纸
1,470 阅读
2
Nacos持久化MySQL问题-解决方案
932 阅读
3
Docker搭建Typecho博客
752 阅读
4
滑动时间窗口算法
728 阅读
5
Nginx反向代理微服务配置
699 阅读
生活
解决方案
JAVA基础
JVM
多线程
开源框架
数据库
前端
分布式
框架整合
中间件
容器部署
设计模式
数据结构与算法
安全
开发工具
百度网盘
天翼网盘
阿里网盘
登录
Search
标签搜索
java
javase
docker
java8
springboot
thread
spring
分布式
mysql
锁
linux
redis
源码
typecho
centos
git
map
RabbitMQ
lambda
stream
少年
累计撰写
189
篇文章
累计收到
24
条评论
首页
栏目
生活
解决方案
JAVA基础
JVM
多线程
开源框架
数据库
前端
分布式
框架整合
中间件
容器部署
设计模式
数据结构与算法
安全
开发工具
百度网盘
天翼网盘
阿里网盘
页面
关于
友链
搜索到
1
篇与
的结果
2022-04-21
安全发布对象,详解各种单例模式
安全发布对象什么是安全发布?发布对象:使一个对象能够被当前范围之外的代码所使用代码示例package com.yanxizhu.demo.concurrency.unSafePublish; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; import lombok.extern.slf4j.Slf4j; import java.util.Arrays; /** * @description: 安全发布,这个例子是线程不安全的 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/21 21:45 * @version: 1.0 */ @Slf4j @UnThreadSafety public class UnSafePublish { private String[] states = {"a", "b", "c"}; public String[] getStates() { return states; } public static void main(String[] args) { UnSafePublish unSafePublish = new UnSafePublish(); log.info("{}", Arrays.toString(unSafePublish.getStates())); unSafePublish.getStates()[0] = "d"; log.info("{}", Arrays.toString(unSafePublish.getStates())); } }运行结果:21:48:00.633 [main] INFO com.yanxizhu.demo.concurrency.unSafePublish.UnSafePublish - [a, b, c] 21:48:00.636 [main] INFO com.yanxizhu.demo.concurrency.unSafePublish.UnSafePublish - [d, b, c]说明:上面代码,可以通过对象,调用getStates()方法获取数据,并可以外部直接修改里面的值。这样states的值是不安全的。对象溢出对象逸出:一种错误的发布。当一个对象还没有构造完成时,就使它被其他线程所见代码示例package com.yanxizhu.demo.concurrency.unSafePublish; import lombok.extern.slf4j.Slf4j; /** * @description: 对象溢出 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/21 21:53 * @version: 1.0 */ @Slf4j public class Escape { private int thisCanBeEascpe = 0; public Escape() { new InnerClass(); } private class InnerClass { public InnerClass() { log.info("{}", Escape.this.thisCanBeEascpe); } } public static void main(String[] args) { new Escape(); } }输出结果:21:55:01.416 [main] INFO com.yanxizhu.demo.concurrency.unSafePublish.Escape - 0说明:Escape对象还没构造完,就被new InnerClass()线程使用Escape.this.thisCanBeEascpe。安全发布对象4种方法在静态初始化函数中初始化一个对象引用将对象的引用保存到volatile类型域或者AtomicReference对象中将对象的引用保存到某个正确构造对象的final类型域中将对象的引用保存到一个由锁保护的域中单例-懒汉模式代码实例,线程不按钮package com.yanxizhu.demo.concurrency.singleton; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; /** * @description: 单例-懒汉模式 * 在第一次使用时创建 * 单线程下没问题,多线程下可能出现问题 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/21 22:05 * @version: 1.0 */ @UnThreadSafety public class SingLetonLazyMode { //私有构造方法 private SingLetonLazyMode() {} //实例对象 private static SingLetonLazyMode instance = null; //静态工厂方法 public static SingLetonLazyMode getInstance() { //注意:多线程下问题,当2个线程同时判断到不为null,是都会调用私有构造方法,创建2个示例对象。 // 如果在构造方法中有对环境一些设置,2次执行会出现一些错误 if (null == instance) { instance = new SingLetonLazyMode(); } return instance; } }说明:上面的单例-懒汉模式是线程不安全的。多线程下问题,当2个线程同时判断到不为null,是都会调用私有构造方法,创建2个示例对象。如果在构造方法中有对环境一些设置,2次执行会出现一些错误。单例-饿汉模式代码实例,线程按钮package com.yanxizhu.demo.concurrency.singleton; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; /** * @description: 单例-饿汉模式 * 类装载时创建,线程安全的 * 不足: 1、如果私有构造方法里面有过多的设置,会加载很慢 * 2、每次都会创建示例对象,造成资源浪费 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/21 22:20 * @version: 1.0 */ @ThreadSafety public class SingLetonHungryManMode { private SingLetonHungryManMode() {} private static SingLetonHungryManMode instance = new SingLetonHungryManMode(); public static SingLetonHungryManMode getInstance() { return instance; } }说明:单例-饿汉模式,类装载时创建,线程安全的。不足地方:1、如果私有构造方法里面有过多的设置,会加载很慢。2、每次都会创建示例对象,造成资源浪费。使用需要考虑:私有构造方法里面是否有过多设置,创建对象是否被使用。单例-懒汉模式改进(synchronized)代码实例,线程安全,但是不推荐使用,性能不太好package com.yanxizhu.demo.concurrency.singleton; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import com.yanxizhu.demo.concurrency.annotation.UnRecommend; /** * @description: 单例-懒汉模式(synchronized保证线程保证线程安全) * 在第一次使用时创建 * 单线程下没问题,多线程下通过synchronized保证线程只被执行一次,线程安全 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/21 22:05 * @version: 1.0 */ @ThreadSafety @UnRecommend public class SingLetonLazyModeSynchronized { //私有构造方法 private SingLetonLazyModeSynchronized() {} //实例对象 private static SingLetonLazyModeSynchronized instance = null; //静态工厂方法 public static synchronized SingLetonLazyModeSynchronized getInstance() { //注意:多线程下问题,当2个线程同时判断到不为null,是都会调用私有构造方法,创建2个示例对象。 // 如果在构造方法中有对环境一些设置,2次执行会出现一些错误 if (null == instance) { instance = new SingLetonLazyModeSynchronized(); } return instance; } }说明:synchronized保证线程只能同时被执行一次,但是带来了性能上的开销。因此是线程安全但不推荐的写法。单例-懒汉模式改进(双重同步锁单例)代码实例,线程不安全的package com.yanxizhu.demo.concurrency.singleton; import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety; /** * @description: 单例-懒汉模式(双重同步锁单例) * 线程不安全 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/21 22:05 * @version: 1.0 */ @UnThreadSafety public class SingLetonLazyModeSynchronized { //私有构造方法 private SingLetonLazyModeSynchronized() {} //实例对象 private static SingLetonLazyModeSynchronized instance = null; //静态工厂方法 public static SingLetonLazyModeSynchronized getInstance() { if (null == instance) { //双重检测机制 //当第一个线程执行后,已经实例化一个对象了,第二个线程再次判断兑现是否实例。 //线程不安全问题所在: // synchronized(SingLetonLazyModeSynchronized.class) { //同步锁 if(null == instance) { instance = new SingLetonLazyModeSynchronized(); } } } return instance; } }说明:instance = new SingLetonLazyModeSynchronized();分为3步骤。1、分配对象的内存空间。2、初始化对象。3、设置instance指向刚分配的内存。问题分析:多线程情况下,上面3步,可能发生指令重排。JVM和CPU优化,发生了指令重排。因为指令2和3没有直接关联,所以上面3步指令可能优化重排成:1、分配对象的内存空间。3、设置instance指向刚分配的内存。2、初始化对象。当第一个线程执行instance = new SingLetonLazyModeSynchronized();设置对象指向刚分配的内存地址,还没执行2初始化对象时,第二个线程判断对象的执行步为空,直接返回对象,此时由于2初始化对象还没执行,导致调用对象报错。单列-懒汉模式(volatile+双重检测机制)最终版代码实例,线程安全,懒汉模式最终版package com.yanxizhu.demo.concurrency.singleton; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; import com.yanxizhu.demo.concurrency.annotation.UnRecommend; /** * @description: 单例-懒汉模式(volatile+双重检测机制单列) 线程安全 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/21 22:05 * @version: 1.0 */ @ThreadSafety public class SingLetonLazyModeSynchronizedDoubleSyncVolatile { //私有构造方法 private SingLetonLazyModeSynchronizedDoubleSyncVolatile() {} //实例对象 //volatile禁止指令重排 private volatile static SingLetonLazyModeSynchronizedDoubleSyncVolatile instance = null; //静态工厂方法 public static SingLetonLazyModeSynchronizedDoubleSyncVolatile getInstance() { if (null == instance) { //双重检测机制 synchronized (SingLetonLazyModeSynchronizedDoubleSyncVolatile.class) { //同步锁 if (null == instance) { instance = new SingLetonLazyModeSynchronizedDoubleSyncVolatile(); } } } return instance; } }说明:volatile+双重检测机制,volatile禁止指令重排,双重检测,加同步锁,保证多线程下线程安全。单例-饿汉模式(静态代码块写法)代码实例,错误的,会发生控制在异常package com.yanxizhu.demo.concurrency.singleton; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; /** * @description: 单例-饿汉模式,静态代码写法 * 注意:静态代码和静态域的顺序,不然会导致空指针 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/21 22:20 * @version: 1.0 */ @ThreadSafety public class SingLetonHungryManModeStatic { private SingLetonHungryManModeStatic() {} //静态代码块 static{ instance = new SingLetonHungryManModeStatic(); } //静态作用域 private static SingLetonHungryManModeStatic instance = null; public static SingLetonHungryManModeStatic getInstance() { return instance; } public static void main(String[] args) { System.out.println(getInstance().hashCode()); System.out.println(getInstance().hashCode()); } }输出结果:Exception in thread "main" java.lang.NullPointerException at com.yanxizhu.demo.concurrency.singleton.SingLetonHungryManModeStatic.main(SingLetonHungryManModeStatic.java:30)错误原因:静态代码和静态域的顺序,导致空指针代码调整后,正确代码package com.yanxizhu.demo.concurrency.singleton; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; /** * @description: 单例-饿汉模式,静态代码写法 * 注意:静态代码和静态域的顺序,不然会导致空指针 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/21 22:20 * @version: 1.0 */ @ThreadSafety public class SingLetonHungryManModeStatic { private SingLetonHungryManModeStatic() {} //静态作用域 private static SingLetonHungryManModeStatic instance = null; //静态代码块 static{ instance = new SingLetonHungryManModeStatic(); } public static SingLetonHungryManModeStatic getInstance() { return instance; } public static void main(String[] args) { System.out.println(getInstance().hashCode()); System.out.println(getInstance().hashCode()); } }输出结果:75457651 75457651单例-枚举模式线程安全最终推荐版本时枚举模式的单例。示例代码:package com.yanxizhu.demo.concurrency.singleton; import com.yanxizhu.demo.concurrency.annotation.Recommend; import com.yanxizhu.demo.concurrency.annotation.ThreadSafety; /** * @description: 单例-枚举模式,线程最安全的,推荐使用的 * @author: <a href="mailto:batis@foxmail.com">清风</a> * @date: 2022/4/21 23:11 * @version: 1.0 */ @ThreadSafety @Recommend public class SingLetonEnum { //私有构造方法 private SingLetonEnum() {}; public static SingLetonEnum getInstance() { return SingLeton.INSTANCE.getSingLetonEnum(); }; private enum SingLeton { INSTANCE; private SingLetonEnum singLetonEnum; //JVM保证这个方法绝对只会被执行一次 SingLeton(){ singLetonEnum = new SingLetonEnum(); } public SingLetonEnum getSingLetonEnum() { return singLetonEnum; } } }说明:枚举的构造方法,JVM保证这个方法绝对只会被执行一次。线程安全,推荐使用的单例模式-枚举模式。比饿汉模式更能保证安全,比懒汉模式更能保证性能。枚举模式只有使用时调用一次,不会造成资源浪费。总结:饿汉模式:有2种写法,最后这种饿汉模式注意静态代码块和作用域顺序。懒汉模式:只有最终版(volatile+双重检测机制)正确,其它都存在线程安全或性能问题。单例模式,线程安全,最终推荐枚举模式。
2022年04月21日
206 阅读
0 评论
3 点赞