深入谈谈Java最简单的单例设计模式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入谈谈Java最简单的单例设计模式相关的知识,希望对你有一定的参考价值。

  单例设计模式是23种设计模式里面最简单的,但是要彻底理解单例,还是需要下一点功夫的。

单例一般会分为饿汉模式和懒汉模式

 饿汉模式:

1 public class Singleton
2 {
3     private static Singleton singleton = new Singleton();
4 
5     public static Singleton getInstance()
6     {
7         return singleton;
8     }
9 }

但是在一些系统应用环境中,这个单例对象可能比较大,在类加载的时候就初始化对象会增加系统启动压力,还会对系统资源造成浪费。所以就有了懒汉模式,只有在第一次调用的时候才创界对象实例。

懒汉模式:

 1 public class Singleton
 2 {
 3     private static Singleton singleton;
 4 
 5     public static Singleton getInstance()
 6     {
 7         if (singleton == null)
 8         {
 9             singleton = new Singleton();
10         }
11         return singleton;
12     }
13 }

但是在多线程的环境中,以上内容就会有问题了。由于没有同步,不同的线程可能同时进入if语句,然后分别创建了两个实例,这时候Singleton就不再是单列了。

于是就有了双重空判断版本

public class Singleton
{
    private static Singleton1 singleton;

    public static Singleton1 getInstance()
    {
        if (singleton == null)
        {
            synchronized (Singleton1.class)
            {
                if (singleton == null)
                    singleton = new Singleton();
            }
        }
        return singleton;
    }
}

网上很多资料说,这种写法也不是线程安全的,singleton字段必须定义为volatile才行。但实际上,以上代码其实并没有线程安全问题,因为Singleton1这个类并没有状态量。举个例子,以下代码才是非线程安全的:

public class WrongSingleton
{
    private static WrongSingleton singleton;
    
    public Object state = new Object();

    public static WrongSingleton getInstance()
    {
        if (singleton == null)
        {
            synchronized (WrongSingleton.class)
            {
                if (singleton == null)
                    singleton = new WrongSingleton();
            }
        }
        return singleton;
    }
}

由于cpu指令重排序的存在,我们无法确认singleton对象引用和state对象引用回写到内存的顺序,如果Singleton对象的引用已经由线程A回写到了内存,而对象内部持有的state字段还未完成回写,那么此时线程B调用getInstance()方法后,将得到一个错误的Singleton对象。其state引用为null。

要解决这个问题有两个办法:

一、把 private static WrongSingleton singleton; 改为  private static volatile Singleton singleton; 由于volatile 的可见性语意,所有对volatile变量的修改,都会立即回写到主存,所以在Singleton构造函数返回前,state对象就已经回写到主存了。

二、把state 对象定义为final字段。由于final语意,final对象在构造函数完成后,其值的可见性对所有线程保持一致。

 

以上是关于深入谈谈Java最简单的单例设计模式的主要内容,如果未能解决你的问题,请参考以下文章

深入单例模式 - Java实现

Android设计模式应用 谈谈Android中的单例模式

Android设计模式应用 谈谈Android中的单例模式

Android设计模式应用 谈谈Android中的单例模式

如何写一个简单的单例模式?

一日一技:Python 下面最简单的单例模式写法