单例模式的几种实现方式

实现方式大致分为两种

  • 懒汉模式
  • 饿汉模式

懒汉模式:在第一次使用该对象时,才会初始化实例,以免了资源的浪费,同时,需要考虑的是线程安全问题。

饿汉模式:在类初始化时就需要创建一个实例对象出来,当时并不一定会使用该对象,可能会造成资源的浪费,好处是不用考虑安全问题。

下面看下几种常见的实现方式:

首先看懒汉模式:

1、线程非安全版本,可在单线程下使用

/**
 * 懒汉式单例,线程不安全,只有在第一次调用时才会初始化一次,
 * 但是线程不安全,如果在初始化时需要消耗大量的资源,则会造成资源的浪费,同时,在并发场景中,可能造成变量的变化等问题。
 * @author woniu
 *
 */
public class Singleton1
{
    private Singleton1(){}
    private static Singleton1 instance = null;
    
    public static Singleton1 getInstance()
    {
        if (instance == null)
        {
            instance = new Singleton1();
        }
        return instance;
    }
}

关于懒汉模式的几种线程安全版本,详细的说明已在类中说明,不在单独说明。

1、在getInstance方法上加同步

/**
 * 懒汉式单例,线程安全,与第一种无异,仅是通过synchronized,将getInstance实现为了同步方法,
 * 但是,这就造成了getInstance方法,仅能同时只有一个线程调用,但是,在除去第一次初始化外,我们大多数情况下,并不需要防止同步问题。
 * @author woniu
 */
public class Singleton2
{
    private Singleton2(){}
    private static Singleton2 instance = null;
    
    public static synchronized Singleton2 getInstance()
    {
        if (instance == null)
        {
            instance = new Singleton2();
        }
        return instance;
    }
}

2、双重检查锁定

/**
 * 此方法被称为双重校验锁,在示例2的基础之上将同步方法,修改为了同步代码块,仅是在需要初始化时,才需要加锁,这样就避免了在大多数情况下不需要同步的问题。
 * 关于之所以在同步方法块中再次进行判断的原因:根据并发编程实战中的提到的“先检查后执行”的操作是非原子性的,简而言之就是,避免用一个过期的变量作为当前的判断标准。
 * 连接:http://www.cnblogs.com/woniu4/p/8284244.html
 * @author woniu
 *
 */
public class Singleton3
{
    private Singleton3(){}
    private volatile static Singleton3 instance = null;
    
    public static Singleton3 getInstance()
    {
        if (instance == null)
        {
            synchronized(Singleton3.class)
            {
                if (instance == null)
                {
                    instance = new Singleton3();
                }
            }
        }
        return instance;
    }
}

3、静态内部类

/**
 * 单例同样可以通过内部类的方式实现,这样就避免了同步带来的性能开销(虽说现在synchronize方法已经做了很大的优化,对性能的影响已经降低了很多,但终究还是有一定影响的。)
 * 虽说这种方式比较好,但是在我们当前项目中,似乎大家都比较懒,直接用了方法2中的模式,毕竟,当前的工程性项目,并没有对项目性能有极高的要求。
 * @author woniu
 *
 */
public class Singleton4
{
    private Singleton4(){};
    
    private static class LasyHolder
    {
        private static final Singleton4 INSTANCE = new Singleton4();
    }
    
    public static Singleton4 getInstance()
    {
        return LasyHolder.INSTANCE;
    }
}

饿汉模式:

/**
 * 饿汉模式,通过在类初始化时,已经实例化,这样本身就是线程安全的。
 * @author woniu
 *
 */
public class Singleton5
{
    private Singleton5(){}
    private static final Singleton5 INSTANCE = new Singleton5();
    
    public static Singleton5 getInstance()
    {
        return INSTANCE;
    }
}

最后有一种通过枚举实现的方式,算是一种比较新的方式吧。当前不清楚具体归属类型,暂且单列出来。

/**
 * 枚举模式,没有使用过,仅是博客或者书见过这种方式,不仅能避免线程同步问题,而且还能防止反序列化重新创建新的对象,日后工作中,有类似需要单例场景中,可以考虑使用一下,写法还是十分简单的。
 * @author woniu
 *
 */
public enum Singleton6
{
    INSTANCE;
    
    public String testMethod()
    {
        return "test enum instance";
    }
    public static void main(String[] args)
    {
        String str = INSTANCE.testMethod();
        System.out.println(str);
    }
}

 

posted @ 2018-01-15 11:52  woniu4  阅读(237)  评论(0编辑  收藏  举报