- 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
- 在我们的系统中,有些对象其实只需要一个,比如说,线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。
- 这类对象只能有一个对象,制造多个可能会导致一些问题的产生:比如程序的行为异常、资源使用过量、或者不一致性的结果
- 优点:
- 对于频繁使用的对象,可以省略创建对象所花费的时间
- 由于 new 操作的次数减少,对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间
- 饿汉方式:全局的单例实例在类加载时构建
- 懒汉方式:全局的单例模式在第一次被使用时构建
- 饿汉方式
public class Singleton { //在静态初始化器中创建单例实例,这段代码保证了线程安全 private static Singleton uniqueInstance = new Singleton(); //Singleton类只有一个构造方法并且是被private修饰的,所以用户无法通过new方法创建该对象实例 private Singleton(){} public static Singleton getInstance(){ return uniqueInstance; } }
-
- JVM 在加载这个类时就创建了此唯一的单例实例,不会存在多个线程创建多个实例的情况,所以线程安全
- 缺点:这个单例即便没有被使用也会被创建,在类加载之后就被创建,内存就浪费了
- 懒汉方式(添加 synchronized)
public class Singleton { private static Singleton uniqueInstance; private Singleton (){ } //没有加入synchronized关键字的版本是线程不安全的 public static synchronized Singleton getInstance() { //判断当前单例是否已经存在,若存在则返回,不存在则再建立单例 if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } }
-
- 在第一次被使用时创建,如果单例已经被创建了,再次调用接口将不会重新创建新的对象,而是直接返回之前创建的对象
- 优点:如果某个单例使用的次数很少,并且创建单例消耗的资源较多,那么就需要实现单例的按需创建,使用懒汉模式是个不错的选择
- 缺点:效率低,第一次加载需要实例化,反应稍慢
- 双重检查单例(DCL实现单例)
public class Singleton { //volatile保证,当uniqueInstance变量被初始化成Singleton实例时,多个线程可以正确处理uniqueInstance变量 private volatile static Singleton uniqueInstance; private Singleton() { } public static Singleton getInstance() { //检查实例,如果不存在,就进入同步代码块 if (uniqueInstance == null) { //只有第一次才彻底执行这里的代码 synchronized(Singleton.class) { //进入同步代码块后,再检查一次,如果仍是null,才创建实例 if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; } }
-
- 利用双重检查加锁,首先检查实例是否已经创建,如果尚未创建,才进行同步。
- 优点:资源利用率高,进行了双重的判断,第一层判断主要避免了不必要的同步
- 缺点:第一次加载时稍慢。
- 静态内部类实现单例
public class Singleton { private Singleton() { } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getUniqueInstance() { return SingletonHolder.INSTANCE; } }
-
- 利用了类加载机制来保证只创建一个实例,与饿汉模式一样,也是利用了类加载机制,因此不存在多线程并发的问题
- 不同的是,是在内部类里面去创建对象实例,这样的话,只要应用中不使用内部类,JVM 就不会去加载这个单例类,从而实现了懒汉方式的延迟加载
- 枚举类实现单例
public enum Singleton { INSTANCE; private String objName; public void doSomething() {} }
-
- 相对于其他单例来说,写法最为简单,并且任何情况下都是单例的。jdk 1.5 之后才有的。