码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2017-08-24 16:09:35      阅读:220      评论:0      收藏:0      [点我收藏+]

标签:环境   多线程   就会   饿汉   instance   启动   需要   网上   增加   

  单例设计模式是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最简单的单例设计模式

标签:环境   多线程   就会   饿汉   instance   启动   需要   网上   增加   

原文地址:http://www.cnblogs.com/mengzhucanyun/p/7423430.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!