单例模式是设计模式中使用最为普遍的模式之一。它是一种对象创建模式,用于产生一个对象的实例,可以确保系统中的一个类只产生一个实例对象。在java中可以有2个好处
1.对于频繁使用的对象,可以省去对象创建的时间,节省系统开销。
2.由于new操作的次数减少,所有对系统内存的使用频率也降低了,这将会减少GC的压力。
单利模式的核心就是通过一个接口返回唯一一个对象实例,看下面的代码
public class Singleton { private Singleton() { System.out.println("singleton is create"); } private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } }
从上面的代码可以看出,单例类必须要有一个私有(private)的构造函数,只有这样,才能确保该类不会再系统中被实例化,还有instance成员变量和getIntance()方法必须是静态的(static)。
上面这种比较简单的,这种方式不足之处是无法对instance实例做延迟加载,假如单例创建过程很慢,而instance又是静态的,因此在JVM加载单例类时,单例对象就会被创建,如果这个单例类又需要做别的事情的时候,依然会去初始化这个变量去产生实例,不管有没有使用到它,
public class Singleton { private Singleton() { System.out.println("singleton is create"); } private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } public static void getString() { System.out.println("get string"); } public static void main(String[] args) { // Singleton.getInstance(); Singleton.getString(); } }
结果显示:
singleton is create get string
所以这个时候就需要引入延迟加载机制。
public class LazySingleton { private LazySingleton() { System.out.println("LazySingleton is create"); } private static LazySingleton instance = null; public static synchronized LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } public static void getString() { System.out.println("get string"); } public static void main(String[] args) { // Singleton.getInstance(); LazySingleton.getString(); } }
结果显示:
get string
这样就达到了延迟加载的效果,首先instance为null,保证启动时没有 额外的负载,getInstance()会判断单利是否存在,存在则返回,不存在则创建,getInstance()需要时同步的,否则在多线程环境下会出现问题,比如线程1正在创建单例对象,在赋值之前,线程2则可能判断instance为null;所以线程2也会去创建实例对象,从而导致多个实例对象被创建,所以需要加入同步关键词来保证只有一个实例对象被创建。
这种方式虽然实现了延迟加载,但是加入同步,导致效率非常低。
所以还有一种方式:类部类的方式
public class Singleton { private Singleton() { System.out.println("Singleton is create"); } private static class SingletonHolder { private static Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; } }
这种方式避免了线程不安全,延迟加载,效率高。
还有几种方式:双重校验
public class Singleton { private static volatile Singleton singleton; private Singleton() {} public static Singleton getInstance() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
进行了两次if (singleton == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象。这样的优点:线程安全;延迟加载;效率较高。