您的位置:首页 > 编程语言 > Java开发

java单例模式的线程安全问题

2012-10-24 13:32 183 查看
传统的单例模式有两种:

第一种,优点:简单,可靠。可以保证在一个类加载器中只有一个实例。

缺点:类在被初始化的时候就会创建一个实例,不管以后会不会用到。

但是我个人认为这种缺点说的实在是有点勉强。

首先此类的实例只有在初始化的时候才会创建。网上有很多说的是在被加载的时候创建,这是严重错误的。

关于类的加载和初始化,可以参考类加载器的介绍。

这种缺点成立的情况为,此类被初始化了,但以后我们不会使用,因此白白创建了一个对象。

但是,我认为,初始化而以后不会使用的情况是几乎不太可能发生的。(但是有可能发生)

public class Singleton{

    private static Singleton instance = new Singleton();

   private Singleton() {

    }

    public static Singleton getInstance() {

        return instance;

    }

}

 

第二种,可以实现一个类加载器中只有一个实例,因为使用了同步,此方式效率极其低。

public class Singleton{

    private static Singleton instance;

   

    private Singleton() {

    }

   

    public static synchronized  Singleton getInstance() {

        if(instance == null) 

            instance = new Singleton();

        return instance;

    }

}

 

double check 方式,可以实现一个类加载器中只有一个实例,并且只有在最初没有实例的情况下才会同步,因此不会有性能上的问题。

public class Singleton {

    private static Singleton instance;

    private Singleton(){

    }

    public static Singleton getInstance(){

        if (instance == null) {

            synchronized (Singleton.class) {

                if (instance == null) {

                    instance = new Singleton();

                }

            }

        }

        return instance;

    }

}

 

好了,那么我们现在有两个选择,第一种方式和第三种方式。

那么哪个更好一些呢?

首先,这两种方式在效率上几乎是相同的。

如果真的出现了只有初始化以后不会使用的情况(虽然这个概率很低,调用Class.forName("SomeClass“)或者用其他方式初始化,但以后再也不使用这个类的实例)

那么当然我们不愿意白白创建一个对象,选择第三种方式无疑是较好的。

如果不会出现这种情况,那么第一种方式是较好的。

如果让我选,那么我会选择第一种方式,简洁,可靠,效率比第三种方式(假设该实例没有创建,那么第一个线程在getInstance中需要获取同步锁,然后才能创建实例,并且以后再getInstance的时候都要判断instance是为空)更好。

毕竟有谁会初始化一个类,但以后不会使用它的instance呢? 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: