Java的单例模式常见的分为懒汉式、饿汉式、静态内部类、枚举
通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数额控制并节约系统资源。
饿汉式:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }
特点:
在这个类初始化时就创建了对象, 每次调用都返回同一个对象。
饿汉模式是线程安全的,可以直接用于多线程而不会出现问题。但是不需要这个对象时,对象就会占用内存空间。
懒汉式:
public class Singleton { private static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if(instance == null){ instance =new Singleton(); } return instance; } }
特点:
在调用获取对象的方法时判断, 如果没有这个对象才会创建。
这样在多线程的环境下会存在线程安全问题,JVM出于对效率的考虑,是在happens-before原则内(out-of-order)乱序执行。
懒汉式线程安全问题解决方法:DCL模式(double-check-locking)
class Singleton { public static Bank instance = null; public Singleton(){ } //效率更高的、线程安全的懒汉模式 public static Singleton getInstance(){ //外面加一层判断,若对象不为Null,就让后面的线程直接返回对象,不用再排队挤进去 if(instance == null){ synchronized (Singleton.class){//使用synchronized关键字,保证只有一次只有一个线程进入,创建实例对象 if(instance == null){ instance = new Singleton(); } } } return instance; } }
静态内部类:
public class SingleTon{ private SingleTon(){} private static class SingleTonHoler{ private static SingleTon INSTANCE = new SingleTon(); } public static SingleTon getInstance(){ return SingleTonHoler.INSTANCE; } }
特定:
这是官方推荐的。外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
枚举:
public enum SingleTon{ INSTANCE; public void method(){ //TODO } }
特点:
枚举在java中与普通类一样,都能拥有字段与方法,而且枚举实例创建是线程安全的,在任何情况下,它都是一个单例。我们可直接以下面这种方式调用。
SingleTon.INSTANCE