八种单例设计模式
- 饿汉式-两种写法
- 懒汉式 lazy loading (第四种写法完美)
- 静态内部类方法(完美)
- 枚举类实现单例 (完美中的完美,但是一般用上面几种)
饿汉式
两种写法在效果上没有什么区别。
第一种写法
/**
* 饿汉式
* 在类加载到内存时就实例化一个对象,jvm保证线程安全。
* 简单实用,推荐使用。
* 唯一缺点,就算你不用它,他也会加载,浪费内存。
*/
public class Mgr01 {
private static final Mgr01 INSTANCE = new Mgr01();
private Mgr01(){}
public static Mgr01 getInstance(){
return INSTANCE;
}
}
第二种写法
public class Mgr02 {
private static final Mgr02 INSTANCE;
/**
* 实例化代码写在静态代码块中
*/
static {
INSTANCE = new Mgr02();
}
private Mgr02(){}
public static Mgr02 getInstance(){
return INSTANCE;
}
}
懒汉式
在初次使用时进行实例化,之后不再进行实例化。
第一种写法(有线程安全问题),如果多个线程同时来获取示例可能引发线程安全问题,导致实例被创建多次。
public class Mgr03 {
private static Mgr03 INSTANCE;
private Mgr03(){}
public static Mgr03 getINSTANCE() {
if (INSTANCE == null){
INSTANCE = new Mgr03();
}
return INSTANCE;
}
}
第二种写法,加synchronized 保证线程安全。问题:性能下降。
public class Mgr04 {
private static Mgr04 INSTANCE;
private Mgr04(){}
/*
* 此处增加 synchronized 来保证只有一个示例对象。性能会下降。
*/
public static synchronized Mgr04 getINSTANCE() {
if (INSTANCE == null){
INSTANCE = new Mgr04();
}
return INSTANCE;
}
}
第三种写法,依然有问题,同样是线程安全问题。
public class Mgr05 {
private static Mgr05 INSTANCE;
private Mgr05(){}
public static Mgr05 getINSTANCE() {
if (INSTANCE == null){
// 此处堆积线程发生多次实例化
synchronized (Mgr05.class){
INSTANCE = new Mgr05();
}
}
return INSTANCE;
}
}
第四种写法,完美写法。
public class Mgr06 {
// volatile 用来防止极小概率发生的指令重排序导致的错误。追求完美要加
private static volatile Mgr06 INSTANCE;
private Mgr06(){}
public static Mgr06 getINSTANCE() {
if (INSTANCE == null){ // 第一次验证
synchronized (Mgr06.class){
if (INSTANCE == null){// 第二次验证
INSTANCE = new Mgr06();
}
}
}
return INSTANCE;
}
}
静态内部类方式
这种方式完美。由静态内部类来实现懒加载,和 jvm 实现线程安全。
public class Mgr07 {
private Mgr07(){}
private static class Mgr07Holder{
private static final Mgr07 INSTANCE = new Mgr07();
}
private Mgr07 getInstance(){
return Mgr07Holder.INSTANCE;
}
}
枚举类实现
也是完美写法。但用的比较少。
public enum Mgr08 {
INSTENCE;
public void m(){
// 这里是单例的方法
System.out.println("业务方法");
}
}