简介
确保一个类只有一个实例,而且自行实例化,并向系统提供这个实例
构造方法不能是public
这个实例是当前类的类成员变量
实现
根据实例化时间的不同可以分为饿汉式、懒汉式
- 饿汉式:在类加载的时候就进行实例化
public class Singleton {
private Singleton(){}
private static Singleton singleton = new Singleton(); //饿汉式
public synchronized static Singleton getInstance(){
return singleton;
}
public static void main(String[] args) {
System.out.println(Singleton.getInstance());
System.out.println(Singleton.getInstance());
}
}
- 懒汉式:在类加载时不进行实例化,在第一次使用的时候进行实例化。注意线程安全。
public class Singleton {
private Singleton(){}
private static Singleton singleton;
public synchronized static Singleton getInstance(){ //线程安全
if(singleton == null){ //判断是否进行实例化
singleton = new Singleton();
}
return singleton;
}
public static void main(String[] args) {
System.out.println(Singleton.getInstance());
System.out.println(Singleton.getInstance());
}
}
我们这样用线程锁把整个方法都锁上会影响性能,因为我们的目的是实例化的代码new Singleton();
仅仅执行一次。实例化一次之后,就不会再进行实例化了,但是这时还会执行同步方法,影响性能,所以我们用同步代码段来保证线程安全并提高返回速度。即:双重检查锁。
public class Singleton {
private Singleton(){}
private volatile static Singleton singleton; //******
public static Singleton getInstance(){
if(singleton == null){
synchronized (Singleton.class) {
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
public static void main(String[] args) {
System.out.println(Singleton.getInstance());
System.out.println(Singleton.getInstance());
}
}
singleton
对象要用volatile
修饰,可以防止指令重排序
什么是指令重排序,一般来说,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。
例外情况
产生多个实例的2种情况
在分布式系统中有多个Java虚拟机,每个虚拟机都有一个实例。
在同一个虚拟机中使用了多个类加载器,产生多个实例。
另外单例模式一般都是无状态的,以工具类的形式提供。