单例的使用场景:
资源共享、多线程、节约资源
单例的注意事项:
1.将构造函数访问修饰符设置为private
——这是确保不会有第二个入口去实例化单例。
2.通过一个静态方法或者枚举返回单例类对象
——getInstance
3.确保单例类的对象有且只有一个,特别是在多线程环境下
——确保资源的正确共享
4.确保单例类对象在反序列化时不会重新构建对象
单例的实现方法:
1.饿汉模式:
类加载时完成初始化,获取迅速,但类加载慢。
/**
* 饿汉式实现单例模式
*/
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
2.懒汉模式
迟加载,第一次调用时初始化。
(1)线程不安全
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
(2)线程安全
花销:每次调用getInstance方法时都需要进行同步
public class Singleton {
private static Singleton instance;
private Singleton() {
}
// synchronized方法,多线程情况下保证单例对象唯一
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3.Double CheckLock
java常用的单例实现模式,第一次判空是为了不必要的同步,第二次判空是在singleton等于null的情况下才创建实例。
public class Singleton {
private volatile static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
// 两层判空,第一层是为了避免不必要的同步
// 第二层是为了在null的情况下创建实例
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
4.静态内部类(推荐)
第一次加载Singleton类时不会初始化instance,只有在第一次调用getInstance()方法时,虚拟机会加载SingletonHolder类,初始化instance。
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
/**
* 静态内部类
*/
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
}
5.枚举实现
6.容器实现