一、介绍
类的单例设计模式,就是采用一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
二、单例模式八种方式
- 饿汉式(静态常量)
- 饿汉式(静态代码块)
- 懒汉式(线程不安全)
- 懒汉式(线程安全,同步方法)
- 懒汉式(线程安全,同步代码块)
- 双重检查
- 静态内部类
- 枚举
1、饿汉式(静态常量)
class Singleton{ // 1.构造器私有化,外部不能new private Singleton(){} // 2.本类内部创建对象实例 private final static Singleton instance = new Singleton(); // 3.提供一个共有的静态方法,返回实例对象 public static Singleton getInstance(){ return instance; } }
优缺点:
- 优点:方法简单,在类装载的时候就完成实例化,避免线程同步。
- 缺点:没有达到 Lazy Loading 的效果。如果从始至终没有使用这个实例,则造成内存浪费。
- 结论:可用,但可能造成内存浪费。
2、饿汉式(静态代码块)
class Singleton{ // 1.构造器私有化,外部不能new private Singleton(){} // 2.本类内部创建对象实例 private static Singleton instance; static { // 静态代码块中创建单例对象 instance = new Singleton(); } // 3.提供一个公有的静态方法,返回实例对象 public static Singleton getInstance(){ return instance; } }
优缺点:
- 方法和第一种类似,只不过将类实例化的过程放在了静态代码块中。优缺点和第一种方式一样。
- 结论:可用,但可能造成内存浪费。
3、懒汉式(线程不安全)
class Singleton{ private static Singleton instance; private Singleton(){} // 提供一个静态的公有方法,当使用到该方法时,才去创建 instance // 即懒汉式 public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
优缺点:
- 优点:起到了 Lazy Loading 的效果,但只能在单线程下使用。
- 缺点:如果在多线程下,一个线程进入了 if(instance == null) 判断语句中,没执行完,另一个线程也通过了这个判断语句,这时就产生了多个实例。
- 结论:在实际开发中,不要使用这种方式。
4、懒汉式(线程安全,同步方法)
class Singleton{ private static Singleton instance; private Singleton(){} // 提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题 public static synchronized Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
优缺点:
- 优点:解决了线程安全问题。
- 缺点:效率太低了。每个线程想获得类的实例都要执行 getInstance() 方法同步,只有第一次实例化才要用到同步锁,后面的要获得该类的实例,直接 return 就行了。
- 结论:在实际开发中,不推荐使用这种方式。
5、懒汉式(线程安全,同步代码块)
class Singleton{ private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ synchronized (Singleton.class){ instance = new Singleton(); } } return instance; } }
优缺点:
- 本质跟上一种方法一样。
- 结论:不推荐使用。
6、双重检查
class Singleton{ private static volatile Singleton instance; private Singleton(){} // 提供一个静态的公有方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题 // 同时保证了效率,推荐使用 public static Singleton getInstance(){ if(instance == null){ synchronized(Singleton.class){ if(instance == null){ instance = new Singleton(); } } } return instance; } }
优缺点:
- 优点:Double-Check 概念是多线程开发中常使用的。延迟加载,效率较高。
- 结论:在实际开发中,推荐使用这种单例设计模式。
7、静态内部类
class Singleton{ private Singleton(){} // 写一个静态内部类,该类中有一个静态属性 private static class SingletonInstance{ private static final Singleton INSTANCE = new Singleton(); } // 提供一个静态的公有方法,直接返回 SingletonInstance.INSTANCE public static synchronized Singleton getInstance(){ return SingletonInstance.INSTANCE; } }
优缺点:
- 原理:这种方式采用了类装载的机制来保证初始化实例时只有一个线程。静态内部类方式在 Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance 方法,才会装载 SingletonInstance 类,从而完成 Singleton 的实例化。类的静态属性只会在第一次加载类的时候实例化,所以在这里,JVM帮助我们保证了线程的安全,在类进行初始化时,别的线程是无法进入的。
- 优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高。
- 结论:推荐使用。
8、枚举
//使用枚举,可以实现单例,推荐 enum Singleton{ INSTANCE; //属性 // public void sayOK(){ // System.out.println("ok~"); // } }
优缺点:
- 借助JDK1.5 中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建对象。
- 结论:推荐使用。
三、单例模式在 JDK 应用的源码分析
- JDK中,java.lang.Runtime 就是经典的单例模式(饿汉式)
- 代码:
四、单例模式注意事项和细节说明
- 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要创建销毁的对象,使用单例模式可以提高系统性能。
- 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new。
- 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)。
来源:https://www.cnblogs.com/xiaoran991/p/12490039.html