博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
单例设计
阅读量:7224 次
发布时间:2019-06-29

本文共 2906 字,大约阅读时间需要 9 分钟。

常见的单例设计模式有以下7种
 
1.懒汉  线程不安全
public class Singleton {    private static Singleton instance;    private Singleton(){}    public static Singleton getInstance(){        if(instance == null){            instance = new Singleton();        }        return instance;    }}

所谓懒汉 , 就是初始化类的时候不创建实例 , 什么时候使用再创建
类似于一种懒加载的机制
但是由于没有线程安全的保障 , 不同的线程很可能会获得不同的实例
所以并不能算是真正严格的单例模式
 
2.懒汉  线程安全
与第一种形式类似 , 只需要在getInstance方法上面加上
synchronized修饰即可
保证了不同的线程只能拿到唯一的实例 , 实现了线程安全和懒加载
但是效率比较低 , 因为在很多的情况下是不需要同步的 
 
3.饿汉
public class Singleton {    private static Singleton instance = new Singleton();    private Singleton(){}    public static Singleton getInstance(){        return instance;    }}

这种方式基于类加载器的机制 , 关于类加载器在后面的笔记里面再做介绍
有效避免了多线程的同步问题 , 但是并没有绝对实现懒加载
( 在这个类被装载的时候才会创建该单例对象
但是导致类被装载的原因可以有多种 , 比如类中的其他静态方法被调用
并不一定是调用了getInstance方法 )
 
4.饿汉 ( 变种 )
与第三种形式类似 , 只是把对象的创建放在static静态子句中进行
但是实际效果并没有本质的区别
同样是在类被装载的时候创建该单例对象
 
5.静态内部类
public class Singleton {    private static class SingletonHolder {        private static final Singleton INSTANCE = new Singleton();    }    private Singleton(){}    public static final Singleton getInstance(){        return SingletonHolder.INSTANCE;    }}

将这个实例包装在一个静态内部类当中 , 实际的效果就是
当Singleton类被装载的时候 , 其中的静态内部类并不会被立即装载
而只有在调用getInstance方法的需要使用这个静态内部类的属性的时候 , SingletonHolder才会被装载
这就彻底解决了饿汉模式所没有彻底解决的懒加载问题
 
6.枚举
枚举本身就是单例的一种扩展
它是线程安全的 , 而且也可以防止反序列化的时候重新创建单例对象 ( 反序列化问题后面会提到 )
可以说是一种最完美的方式
但是枚举这种十分特殊的类平时很少用到 , 实际使用起来可能略有些生疏 
public enum Singleton {    INSTANCE;    //这里也可以写一些这个类的其他方法..}

7.双重校验锁

public class Singleton {    private volatile static Singleton singleton;    private Singleton() {}    public static Singleton getSingleton() {        if (singleton == null) {                synchronized (Singleton.class) {                if (singleton == null) {                    singleton = new Singleton();                }            }        }        return singleton;    }}

使用双重校验锁可以解决线程安全的懒汉模式所带来的性能问题
因为当实例已经创建的时候 , 就不需要进入synchronized代码块
 

序列化与反序列化对单例的破坏
如果一个类实现了Serializable接口 , 那么它的对象就可以被序列化写入到一个文件当中
同样也可以读取这个文件重新获取这个类的对象
但是如果作为一个单例 , 当执行反序列化的时候 , 我们希望拿到的还是这个唯一的对象
但是实际情况是会重新创建出一个对象 
public static void main(String[] args)            throws IOException, ClassNotFoundException{    FileOutputStream fos = new FileOutputStream("tempFile");    ObjectOutputStream output = new ObjectOutputStream(fos);    //将对象序列化写出到文件    output.writeObject(Singleton.getInstance());    output.close();    //从文件中读取内容反序列化为对象    FileInputStream fis = new FileInputStream("tempFile");    ObjectInputStream input = new ObjectInputStream(fis);    Singleton newSingleton = (Singleton) input.readObject();    System.out.println(newSingleton == Singleton.getInstance());    /*比较获得的结果是false,代表这是两个不同的对象*/    input.close();    //删除临时文件    File file = new File("tempFile");    if(file.delete()){        System.out.println("文件删除成功");    }}

解决的办法很简单
就是在这个单例对应的类当中添加一个方法 
或者直接使用上面提到的枚举来构造单例

转载于:https://www.cnblogs.com/programInit/p/6363176.html

你可能感兴趣的文章
Linux find/grep命令
查看>>
【数据结构与算法】(二) c 语言链表的简单操作
查看>>
线程相关参数
查看>>
改造 Android 官方架构组件 ViewModel
查看>>
贾跃亭被指拿恒大的投资款告投资人 总费用超2000万
查看>>
春运守护者 大陆首批台湾籍乘务长黄佳莹
查看>>
潮汕明代皇封御葬古墓受损追踪:当地相关部门介入
查看>>
使用js操作checkbox
查看>>
分享阿里云服务器系列之弹性裸金属服务器
查看>>
Merge k Sorted Lists@LeetCode
查看>>
Hibernate-ORM:15.Hibernate中的Criteria查询
查看>>
Flask從入門到入土(五)——Flask与数据库
查看>>
手动删除木马程序
查看>>
Ebistrategy亦策软件提升天天果园管理效率
查看>>
33个优秀的 jQuery 图片展示插件分享
查看>>
使用Identity Server 4建立Authorization Server (4)
查看>>
Docker
查看>>
精通SpringBoot——第四篇:Spring事件 Application Event
查看>>
ThreadPoolExecutor详解
查看>>
真能“穿墙识人”,MIT人体姿态估计系统创历史最高精度!
查看>>