当前位置:网站首页>详解单例模式
详解单例模式
2022-06-30 17:32:00 【z啵唧啵唧】
文章目录
单例模式
1.饿汉式单例
特点:一上来先实例化对象
存在问题:可能会造成资源空间的浪费
/** * @Description: 饿汉式单例模式 * @Author:啵啵啵啵啵啵唧~~~ * @Date:2022/6/29 */
public class Hungry {
/** * 假如这个类在被创建的时候会开辟很大的数组 * * 那么这个饿汉式单例模式存在的问题就是说可能会造成资源空间的浪费 * 比如现在就是这个类会创建很多的大数组,那么单例模式一上来就是实例化对像 * 如果这个对象后续没有被使用那么就浪费了很多的空间 * 所以根据饿汉式存在的问题引出懒汉式的单例模式 */
private byte[] data1 = new byte[1024 * 1024];
private byte[] data2 = new byte[1024 * 1024];
private byte[] data3 = new byte[1024 * 1024];
private byte[] data4 = new byte[1024 * 1024];
/** * 一个私有的构造方法 */
private Hungry() {
}
/** * 饿汉式单例,一上来不管三七二十一,一上来就先把对象进行加载 */
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance() {
return HUNGRY;
}
}
2.懒汉式单例
//---------------------基础版本单例模式,存在线程安全问题----------------------
public class LazyMan {
/** * 私有构造 */
private LazyMan() {
}
/** * 上来先不实例化对象 */
private static LazyMan lazyMan;
/** * 检测以下对象是否为空,当为空的时候才创建 * @return */
public static LazyMan getInstance() {
if (lazyMan == null) {
lazyMan = new LazyMan();
}
return lazyMan;
}
}
//-----------------------双重检测锁模式版本-----------------------------
public class LazyMan {
/** * 私有构造 */
private LazyMan() {
}
/** * 双重检测锁对象我们给定为volatile进行修饰,防止指令重排,因为: * lazyMan = new LazyMan(); 这个new对象的操作在底层并不是原子性的 * 1. 分配内存空间 * 2. 执行构造方法,初始化对象 * 3. 把这个对象指向这个空间 * 假设现在A线程执行创建实例的代码,底层发生了指令重排 创建对象的三步顺序为 1 3 2 * 意味着线程A还没有初始化对象就指向了空间,假设此时有一个线程B执行到了这里 * 线程B在判断第一个lazyMan==null的时候就为false,因为线程A已经指向了内存空间 * 那么此时线程B就直接返回了这个对象,但是实际上线程A还没有初始化这个对象,所以返回的这个对象是虚无的 * 所以为了创建对象的时候发生指令重排,加一个volatile关键字修饰 */
private volatile static LazyMan lazyMan;
/** * 检测以下对象是否为空,当为空的时候才创建 * @return */
public static LazyMan getInstance() {
//这个第一个lazyMan == null 的作用是为了提高效率,不加这一层的话,每一次都要获得锁,获得锁实际上是很拉效率的操作
if (lazyMan == null) {
synchronized (LazyMan.class) {
if (lazyMan == null) {
lazyMan = new LazyMan();
}
}
}
return lazyMan;
}
}
3.静态内部类获取单例
public class Holder {
/** * 构造器私有 */
private Holder() {
}
public static Holder getInstance() {
return InnerClass.HOLDER;
}
/** * 静态内部类创建实例 */
public static class InnerClass{
private static final Holder HOLDER = new Holder();
}
}
4.反射破环单例模式
正常获取
public static void main(String[] args) {
LazyMan instance1 = LazyMan.getInstance();
LazyMan instance2 = LazyMan.getInstance();
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}

破环一:一个采用正常方式获取单例,一个采用反射的方式获取单例
public static void main(String[] args) throws Exception {
LazyMan instance1 = LazyMan.getInstance();
//获取单例类的构造器
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
//无视私有的构造器
declaredConstructor.setAccessible(true);
//通过反射的方式获取实例
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rdP5yLgq-1656521562320)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/image-20220630000533306.png)]](/img/9a/8f7c062ecdd162353fb1ade4097d83.png)
- 解决方法,改善私有构造器,三重检测锁的方式,我们在单例类的构造方法当中判断一下,instance1是否为空,如果不为空抛出异常
/** * 私有构造 */
private LazyMan() {
synchronized (LazyMan.class) {
if (lazyMan != null) {
//不为空还调用了构造器,说明被反射破坏了,抛出一个异常阻止
throw new RuntimeException("不要试图使用反射破环单例模式!!!");
}
}
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qr4TjQgv-1656521562321)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/image-20220630001048394.png)]](/img/38/6a771ca2386608c1066c9edab0feb4.png)
破环二,不使用类中提供的引用创建对象,每次创建对象都使用反射的方法
public static void main(String[] args) throws Exception {
//获取单例类的构造器
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
//无视私有的构造器
declaredConstructor.setAccessible(true);
//通过反射的方式获取实例
LazyMan instance1 = declaredConstructor.newInstance();
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zRs6OtZs-1656521562322)(C:/Users/zhengbo/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0/Typora%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/image-20220630002101367.png)]](/img/3a/34a9a8223165853929feac48649619.png)
- 这种情况的解决办法,可以通过做一个打标记的方式解决
/** * 红绿灯策略,防止单例杯破坏 */
private static boolean target = false;
/** * 私有构造 */
private LazyMan() {
if (!target) {
target = true;
} else {
throw new RuntimeException("不要试图通过反射的方式破环单例");
}
}

破环三,通过破环类中的字段,破坏红绿灯策略
public static void main(String[] args) throws Exception {
//获取单例类的构造器
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
//无视私有的构造器
declaredConstructor.setAccessible(true);
//获取单例类中的target字段
Field target = LazyMan.class.getDeclaredField("target");
target.setAccessible(true);
//通过反射的方式获取实例
LazyMan instance1 = declaredConstructor.newInstance();
//执行完毕之后,我们将字段的值改为false
target.set(instance1,false);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}

道高一尺魔高一丈!!!
5.枚举的方式,防止单例被破坏
/** * @Description: 枚举的方式防止单例被破坏 * enum本身也是一个类 * @Author:啵啵啵啵啵啵唧~~~ * @Date:2022/6/30 */
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance() {
return INSTANCE;
}
}
class Test {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
EnumSingle instance1 = EnumSingle.INSTANCE;
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
EnumSingle instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
- 枚举类型最终的反编译后是有参构造器
- 反射破坏枚举抛出异常

边栏推荐
- Classic problem of leetcode dynamic programming (I)
- At present, the big guys are joining the two streams of flinksql, cdcmysql and Kafka, and the results are put into MySQL or KA
- What if the apple watch fails to power on? Apple watch can not boot solution!
- Partition marble (multiple knapsack + binary optimization)
- [零基础学IoT Pwn] 环境搭建
- Talk about the SQL server version of DTM sub transaction barrier function
- MySQL cannot find mysql Temporary solution of sock file
- Geoffrey Hinton:我的五十年深度学习生涯与研究心法
- Compilation problems and solutions of teamtalk winclient
- ONEFLOW source code parsing: automatic inference of operator signature
猜你喜欢

Digital intelligent supplier management system solution for coal industry: data driven, supplier intelligent platform helps enterprises reduce costs and increase efficiency

Post office - post office issues (dynamic planning)

System integration project management engineer certification high frequency examination site: prepare project scope management plan

Do you write API documents or code first?

Dropout: immediate deactivation

SaaS project management system solution for the financial service industry helps enterprises tap a broader growth service space

Helping the ultimate experience, best practice of volcano engine edge computing

C# Winform程序界面优化实例

Troubleshooting MySQL for update deadlock

Multipass Chinese document - setting graphical interface
随机推荐
英飞凌--GTM架构-Generic Timer Module
Redis - persistent RDB and persistent AOF
Dependencies tool to view exe and DLL dependencies
hdfs上的数据导入到clickhouse用什么方式最快呢?spark通过jdbc导入,还是hdfs
Openlayers roller shutter map
Multipass中文文档-设置图形界面
ASP. Net generate verification code
EasyNVR平台设备通道均在线,操作出现“网络请求失败”是什么原因?
Volcano engine was selected into the first "panorama of edge computing industry" in China
Compilation problems and solutions of teamtalk winclient
Tensorflow2 ten must know for deep learning
Sign up for Huawei cloud proposition in the "Internet +" competition, and you can take many gifts!
Vscode status bar statusbar
Type ~ storage ~ variable in C #
The company was jailed for nonstandard bug during the test ~ [cartoon version]
TeamTalk WinClient编译问题及解决方案
Advanced customization of uni app [day13]
[cloud resident co creation] Huawei iconnect enables IOT terminals to connect at one touch
Classic problem of leetcode dynamic programming (I)
Advanced embedded application of uni app [day14]