单例模式(Singleton Pattern)是一种简单的对象创建型模式。该模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。
所以要实现单例模式,要做到以下几点:
- 将构造方法私有化,杜绝使用构造器创建实例。
- 需要自身创建唯一的一个实例,并提供一个全局访问入口
饿汉式
所谓饿汉式,就是直接创建出类的实例化,然后用private私有化,对外只用静态方法暴露。
public class Singleton {
// 1、构造私有 判断INSTANCE是否为null,防止通过反射创建新对象
private Singlgton() {
if(INSTANCE != null) {
throw new RunTimeException("单例对象不能重复创建!");
}
}
// 2、私有静态成员变量
private static Singleton INSTANCE = new Singleton();
// 3、公共方法获取实例
public static Singleton getIntance() {
return INSTANCE;
}
// 4、解决反序列化创建实例
public Object readResolve() {
return INSTANCE;
}
}
枚举式
其实,使用枚举也能实现单例模式,不仅能避免多线程同步问题,也能防止反序列化重新创建新的对象。
public enum Singleton {
INSTANCE;
}
//测试
public static void main(String[] args) {
Singleton instance1 = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
运行结果
懒汉式
所谓懒汉式,就是在需要调用的时候再创建类的实例化。
-
线程不安全
起到了懒加载效果,但是只能在单线程使用,多线程会不安全,因为当多个线程并发同时判断instance为空时,就会相应的实例化多个对象。
public class Singleton() { private Singleton(){} private static Singleton INSTANCE; public static Singleton getIntance() { if(INSTANCE == null) { INSTANCE = new Singleton(); } return INSTANCE; } }
-
线程安全
上面线程不安全,那上锁不就好了,使用synchronized关键字。这样虽然解决了线程安全,但其实实例化操作只做一次,而获取实例(即getInstance)的操作是很多次的,把调用的方法加上同步,会大大降低效率。
public class Singleton { private Singleton(){} private static Singleton INSTANCE; public static synchronized Singleton getInstance() { if(INSTANCE == null){ INSTANCE= new Singleton(); } return INSTANCE; } }
-
双重检查
上面代码效率低,那在同步前判断一下有没有实例化不就好了,若没有实例化则用同步方法new一个,否则直接return即可。即所谓的双重检查。
需要用到关键字volatile,防止指令重排。如果不用volatile关键字,就会和线程不安全情形一样,在if判断那会有并发。public class Singleton { private Singleton() {} private static volatile Singleton INSTANCE; public static Singleton getInstance() { if(INSTANCE == null) { synchronized (Singleton.class) { if(INSTANCE == null) { INSTANCE = new Singleton(); } } } return INSTANCE; } }
-
静态内部类
静态内部类在外部类装载时不会实例化,当调用的时候才会装载并实例化,且JVM保证了其装载时的线程安全性。也能保证懒加载和线程安全,有点像自带版的双重检查。
public class Singleton { private Singleton() {} public static synchronized Singleton getInstance() { return SingletonInstance .INSTANCE; } private class SingletonInstance { static Singleton INSTANCE = new Singleton(); } }