前言
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建(单例模式的构造函数是私有的,保证不会被其他类实例化创建
)。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
饿汉模式
public class EHanMode {
private EHanMode(){}
private static EHanMode eHanMode = new EHanMode();
public static EHanMode getInstance(){
return eHanMode;
}
}
是否懒加载:否
是否多线程安全:是
优点:没有加锁,执行效率较高
缺点:类加载时就初始化,浪费内存(可能后面不会用到,但是已经加载了,没有体现需要时再加载)
懒汉模式——线程不安全
public class LanHanMode {
private static LanHanMode lanHanMode= null;
private LanHanMode(){}
public static LanHanMode getInstance(){
if(lanHanMode==null){
lanHanMode = new LanHanMode();
}
return lanHanMode;
}
}
是否懒加载:是
是否多线程安全:否
优点:在需要时才去创建实例(懒加载),节约了内存资源
缺点:线程不安全。比如在多线程下,线程A进入判断条件后,cpu转到线程B,线程B判断lanHanMode为空,创建。然后又转到线程A,线程A又再次创建,存在多个实例
懒汉模式改良1——线程安全
public class LanHanMode1 {
private static LanHanMode1 lanHanMode1= null;
private LanHanMode1(){}
/**
* 加锁防止多线程带来的不安全
* @return
*/
public static synchronized LanHanMode1 getInstance(){
if(lanHanMode1==null){
lanHanMode1 = new LanHanMode1();
}
return lanHanMode1;
}
}
是否懒加载:是
是否多线程安全:是
优点:即实现了懒加载,又保证了多线程并发安全
缺点:单例创建成功后,仍然排队等待获取锁,这样是没有必要的,如果多次调用getInstance(),对性能的损耗就比较大了
懒汉模式改良2——双重校验锁(DCL,即 double-checked locking)
public class LanHanMode2 {
private LanHanMode2(){}
private static LanHanMode2 lanHanMode2 = null;
public LanHanMode2 getInstance(){
if(lanHanMode2==null){
synchronized (LanHanMode2.class){
if(lanHanMode2==null){
lanHanMode2 = new LanHanMode2();
}
}
}
return lanHanMode2;
}
}
是否懒加载:是
是否多线程安全:是
优点:即实现了懒加载,又保证了多线程并发安全,同步代码块外多了一层判空,第一次创建后,后面再次调用就直接返回单例对象,不会执行同步代码块,从而提高了程序性能
缺点:因为Java的指令重排优化,导致其他线程可能会获得不正确的对象(具体可以参考我的这篇文章)
所以加上volatile
关键字禁止指令重排序
public class LanHanMode2 {
private LanHanMode2(){}
private static volatile LanHanMode2 lanHanMode2 = null;
public LanHanMode2 getInstance(){
if(lanHanMode2==null){
synchronized (LanHanMode2.class){
if(lanHanMode2==null){
lanHanMode2 = new LanHanMode2();
}
}
}
return lanHanMode2;
}
}
静态内部类
public class Singleton{
private static class SingletonHolder{
public static Singleton instance = new Singleton();
}
private Singleton(){}
public static Singleton newInstance(){
return SingletonHolder.instance;
}
}
是否懒加载:是
是否多线程安全:是
描述:与饿汉模式相同,利用类加载机制,保证多线程并发安全问题。不一样的是,他在内部类中创建对象实例,这样的话,如果不使用内部类,JVM就不会加载单例类,就不会创建单例对象,实现懒加载。
枚举
public enum Singleton {
//枚举元素本身就是单例
INSTANCE;
//添加自己需要的操作
public void whateverMethod() {
}
}