浅谈单例模式的6种实现方式

问题的提出:

生活中常常会遇到这样的问题,一个国家只能有一个主席,一个学校只能有一个校长…也就是说某些事物具有唯一性,如果多于一个会发生意想不到的事情。这种情况在计算机中也同样存在,因为单例模式应运而生。

单例模式:

单例模式可以说是最简单也是最常见的设计模式,它属于创建型模式,它提供了一种创建对象的最佳方式。这个模式往往是说一个类有且只有一个由自己生成的对象,并且还有一个对外的可供访问该对象的一种方式。(通俗的讲,就是这个类的构造器被私有化了,并且在类里面只实例化了一个对象,如果你需要用到该类对象,你只能通过getInstance()方法获得类自己生成的这个对象)
那么什么时候你需要用到单例模式呢?
比如说:

现在的操作系统大多是多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。例如:日志类(如果不用单例模式,对文件的操作可能会无效,反正会发生很多不可言状的意外)

实现方式:

单例模式的实现方式一般有6种。

0. 懒汉式,线程不安全

这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式懒加载 很明显,不要求线程安全,在多线程不能正常工作。

public class Singleton { 
    private static Singleton INSTANCE; 
    private Singleton (){} 
 
    public static Singleton getInstance() { 
    if (INSTANCE== null) { 
        INSTANCE= new Singleton(); 
    } 
    return INSTANCE; 
    } 
}

1. 懒汉式,线程安全

这种方式具备很好的懒加载,能够在多线程中很好的工作
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。

public class Singleton { 
    private static Singleton INSTANCE; 
    private Singleton (){} 
    public static synchronized Singleton getInstance() { 
    if (INSTANCE== null) { 
        INSTANCE= new Singleton(); 
    } 
    return INSTANCE; 
    } 
}

2. 饿汉式

这种方式比较常用,但容易产生垃圾对象。
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
它基于类加载机制避免了多线程的同步问题,不过,INSTANCE在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance() 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 INSTANCE显然没有达到懒加载的效果。

public class Singleton { 
    private static Singleton instance = new Singleton(); 
    private Singleton (){} 
    public static Singleton getInstance() { 
    return instance; 
    } 
}

3. 双检锁/双重校验锁 double-checked locking

这种方式采用双锁机制,安全且在多线程情况下能保持高性能。(推荐!)
getInstance() 的性能对应用程序很关键。

public class Singleton { 
    private volatile static Singleton singleton; 
    private Singleton (){} 
    public static Singleton getSingleton() { 
    if (singleton == null) { 
        synchronized (Singleton.class) { 
        if (singleton == null) { 
            singleton = new Singleton(); 
        } 
        } 
    } 
    return singleton; 
    } 
}

4. 静态内部类

这种实现方式采用静态内部类的方式,作为单例,直接用classLoader(*jvm类加载机制)*进行处理异步加锁问题,并减少内存消耗,同时实现了懒加载,线程安全
其他的实现方式为解决并发,主要通过使用synchronized来加互斥锁,进行同步控制。但某些情况下,jvm已经隐含的执行了同步,这种情况下就不用自己再来进行同步控制了。

public class Singleton
{
       private Singleton(){}
       
       private static class SingletonHandler {
             private static Singleton singleton = new Singleton();
       }
       
       public static Singleton getInstance(){
             return SingletonHandler.singleton;
       }
}

(枚举是JDK1.5加入的新特性,所以用的人很少)

5. 枚举

这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。由于enum是JDK1.5加入的新特性,对于很多人来说还不是太习惯这种写法,不过这确实是单例模式的最佳解决方案。

public enum Singleton { 
    INSTANCE; 
    public void whateverMethod() { 
    } 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值