设计模式学习——单例模式
一、介绍
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
二、单例模式几种实现
1)饿汉式(推荐)
饿汉式是最简单的单例实现形式,并且具备线程安全特性(由classloader机制保障线程安全),唯一的不足就是不管程序中有没有用到此对象都会被加载进内存,当然个人认为这个缺点影响不大,毕竟如果你都压根不用此对象了那干嘛还要加载呢。
public class DemoManager { private static DemoManager INSTANCE = new DemoManager(); private DemoManager() { } public static DemoManager getInstance() { return INSTANCE; } }
2)懒汉式
懒汉式顾名思义只有在需要的时候加载,懒汉式也有几种写法:
线程不安全版本(不推荐)
public class DemoManager { private static DemoManager demoManager; private DemoManager() { } public static DemoManager getInstance() { if (demoManager == null) { demoManager = new DemoManager(); } return demoManager; } }
线程安全版本(不推荐)
public class DemoManager { private static DemoManager demoManager; private DemoManager() { } public static synchronized DemoManager getInstance() { if (demoManager == null) { demoManager = new DemoManager(); } return demoManager; } }
虽然此版本通过加锁保障了线程安全,但是我们知道加锁是比较消耗资源的操作,在高并发场景下会存在性能问题,因此此版本也不推荐。
3)双重检测版本
此版本可以看作是懒汉式的增强版,既实现懒加载又能保障线程安全且拥有不错的性能,这种方式本质上就是减少不必要的加锁操作。
public class DemoManager { private static DemoManager demoManager; private DemoManager() { } public static synchronized DemoManager getInstance() { if (demoManager == null) { synchronized (DemoManager.class) { if (demoManager == null) { demoManager = new DemoManager(); } } } return demoManager; } }
这个版本的缺点就是比较复杂,那么有没有既简单又完美的实现方式呢?
4)静态内部类式(推荐)
这种方式同样利用了 classloader 机制来保证初始化 INSTANCE 时只有一个线程,它饿汉式不同的是:饿汉式只要 DemoManager 类被装载了,那么 INSTANCE 就会被实例化(没有达到懒加载效果),而这种方式是 DemoManager 类被装载了,INSTANCE 不一定被初始化。因为 InnerManager 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 InnerManager 类,从而实例化 INSTANCE。
public class DemoManager { private static class InnerManager { private static final DemoManager INSTANCE = new DemoManager(); } private DemoManager() { } public static synchronized DemoManager getInstance() { return InnerManager.INSTANCE; } }
5)枚举(推荐)
这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
public enum DemoManager { INSTANCE; public void doSomething() { System.out.println("doSomething"); } }
三、总结
以上就是单例模式的几种写法,个人认为一般情况下饿汉式就能满足我们的需求,除非在某下场景下明确规定需要懒加载那我们在用静态内部类或者枚举形式,