本文共 3018 字,大约阅读时间需要 10 分钟。
参考:
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。
单例模式可以使整个系统拥有一个全局的对象,方便资源的共享和系统行为的协调。
一:饿汉式
public class Singleton { private static Singleton = new Singleton(); private Singleton() {} public static getSignleton(){ return singleton; }}
饿汉式是最简单的,在类加载的时候就被创建,也没有多线程的问题,
但是不能满足延迟加载的需求
二:懒汉式:
public class Singleton { //私有静态实例 private static Singleton singleton; //构造私有 private Singleton() {} public void doSomeThing() { System.out.println("doSomeThing"); } //加锁 public static synchronized Singleton getInstance() { if (singleton == null) { singleton = new Singleton(); } return singleton; }}
懒汉式在用的的时候才考虑第一次创建对象,但是这里会有多线程的问题,多以用synchronized给方法加锁,
但是这里每次访问的时候都是synchronized的,性能会有影响,所以有了第三种
三:双重检查锁锁(double checked locking)
public class Singleton { //私有静态实例 private static volatile Singleton singleton; //构造私有 private Singleton() {} public void doSomeThing() { System.out.println("doSomeThing"); } //加锁 public static Singleton getInstance() { if (singleton == null) { synchronized (Singleton.class){ if (singleton==null) { singleton = new Singleton(); } } } return singleton; }}
这里面解释一下:
1.为什么synchronized内部就还要再检查一次
因为在一个线程进入synchronized内部的时候,另外一个可能进了第一层if了,所以在锁起来的代码内部还要再判断一次
2.为什么要用volatile修饰singleton
volatile关键字可以保证有序性,如果不加这个关键字的话,可能一个线程在synchronized内部new 但还没执行完,另外一个线程得到的实例虽然不为null,但是并没有初始化
singleton = new Singleton() 这条命令执行分为三部分
1.为对象分配内存
2.执行构造方法语句,初始化实例对象
3.把singleton的引用指向分配的内存空间
如果指令重拍为132,则多线程情况下就会有问题!
-------------------------------------------------------------------------------------------------------------------------
上面三种方式是传统的单例模式实现方式
四:静态内部类
public class Singleton { private Singleton() {} public void doSomeThing() { System.out.println("doSomeThing"); } public static Singleton getInstance() { return SingletonHolder.sInstance; } private static class SingletonHolder{ private static Singleton sInstance = new Singleton(); }}
当外部类被加载时,其金泰内部类不会被加载,只有当调用SIngleton.getInstance()方法时,才会加载SingletonHolder并且初始化其成员变量。而类加载时是线程安全的。这样既保证了延迟加载,也保证了线程安全,同时也简化了代码量。
五 枚举单例
参考:
好处:
1.实例的创建线程安全,确保单例
2.防止被反射创建多个实例
3.没有序列化的问题
/** * 使用枚举的单例模式 * * @author yzl * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */public class EnumSingleton{ private EnumSingleton(){} public static EnumSingleton getInstance(){ return Singleton.INSTANCE.getInstance(); } private static enum Singleton{ INSTANCE; private EnumSingleton singleton; //JVM会保证此方法绝对只调用一次 private Singleton(){ singleton = new EnumSingleton(); } public EnumSingleton getInstance(){ return singleton; } }}
public static void main(String[] args) { EnumSingleton obj1 = EnumSingleton.getInstance(); EnumSingleton obj2 = EnumSingleton.getInstance(); //输出结果:obj1==obj2?true System.out.println("obj1==obj2?" + (obj1==obj2));}
转载地址:https://blog.csdn.net/perfectnihil/article/details/91354197 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!