Java 单例模式的七种写法



第一种(懒汉,线程不安全)

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

优缺点: 这种写法 lazy loading 很明显,但是致命的是在多线程中不能正常工作。

第二种(懒汉,线程安全)

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

优缺点:这种写法能够在多线程中很好的工作,而且看起来它也具备很好的 lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。

第三种(饿汉)

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

优缺点:这种方式基于 classloder 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。

第四种(饿汉,变种)

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

优缺点:表面上看起来差别挺大,其实跟第三种方式差不多,都是在类初始化即实例化 instance。

第五种(静态内部类)

public class Singleton {
private static final class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
} private Singleton() {
} public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

优缺点:这种方式同样利用了 classloder 的机制来保证初始化 instance 时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。
因为 SingletonHolder 类没有被主动使用,只有显示通过调用 getInstance 方法时,才会显示装载 SingletonHolder 类,从而实例化 instance。
想象一下,如果实例化 instance 很消耗资源,我想让他延迟加载,另外一方面,我不希望在 Singleton 类加载时就实例化,因为我不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。

第六种(枚举)

public enum Singleton {
INSTANCE; public void whateverMethod() {
}
}

优缺点:这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于 1.5 中才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。

第七种(双重校验锁)

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

优缺点:这个是第二种方式的升级版,俗称双重检查锁定。在 JDK1.5 之后,双重检查锁定才能够正常达到单例效果。

两个问题总结

一、如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些 servlet 容器对每个 servlet 使用完全不同的类装载器,这样的话如果有两个 servlet 访问一个单例类,它们就都会有各自的实例。
二、如果 Singleton 实现了 java.io.Serializable 接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。

  • 对第一个问题修复的办法是
private static Class getClass(String classname) throws ClassNotFoundException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null)
classLoader = Singleton.class.getClassLoader(); return (classLoader.loadClass(classname));
}
  • 对第二个问题修复的办法是
public class Singleton implements java.io.Serializable {
public static Singleton INSTANCE = new Singleton(); protected Singleton() {
} private Object readResolve() {
return INSTANCE;
}
}

参考资料

Java 单例模式的七种写法的更多相关文章

  1. Java设计模式之单例模式(七种写法)

    Java设计模式之单例模式(七种写法) 第一种,懒汉式,lazy初始化,线程不安全,多线程中无法工作: public class Singleton { private static Singleto ...

  2. 单例模式:Java单例模式的几种写法及它们的优缺点

    总结下Java单例模式的几种写法: 1. 饿汉式 public class Singleton { private static Singleton instance = new Singleton( ...

  3. Android设计模式之单例模式的七种写法

    一 单例模式介绍及它的使用场景 单例模式是应用最广的模式,也是我最先知道的一种设计模式.在深入了解单例模式之前.每当遇到如:getInstance()这样的创建实例的代码时,我都会把它当做一种单例模式 ...

  4. Java:单例模式的七种写法

    第一种(懒汉,线程不安全): 1 public class Singleton { 2 private static Singleton instance; 3 private Singleton ( ...

  5. Java:单例模式的七种写法(转载)

    第一种(懒汉,线程不安全): package Singleton; /** * @echo 2013-10-10 懒汉 线程不安全 */ public class Singleton1 { priva ...

  6. Java:单例模式的七种写法[转]

    第一种(懒汉,线程不安全):  1 public class Singleton {   2     private static Singleton instance;   3     privat ...

  7. 【JAVA学习】单例模式的七种写法

    尊重版权:http://cantellow.iteye.com/blog/838473 第一种(懒汉.线程不安全): Java代码   public class Singleton { private ...

  8. Java:单例模式的七种写法<转>

    第一种(懒汉,线程不安全):  1 public class Singleton {   2     private static Singleton instance;   3     privat ...

  9. 温故而知新(java实现)单例模式的七种写法

    第一种(懒汉,线程不安全): Java代码 public class Singleton { private static Singleton instance; private Singleton ...

随机推荐

  1. hexo搭建个人博客

    本文讲述如何用`hexo`搭建个人博客,并托管到`github`.不需要租赁服务器,可完成网站博客的搭建. 安装Hexo安装hexo之前,要先下载安装Node.js和Git,百度搜索找到下载即可.[G ...

  2. 简单去除exe自校验方式

    简单去除exe自校验方式 一.      自校验定义: 这些程序会检查自己有没有被修改,如果发现被修改的话,便会离开或进行其它动作.基本的校检方法包括 checksum, 检查大小, 检查跳转代码,等 ...

  3. for程序员:这些你可能遇到的职场难题,我们帮你整理好了答案

    “迷茫”是当下青年谈论的最多的词汇之一,无论高矮胖瘦富穷美丑,每个人都有自己独特的难题.造成“迷茫”的原因有很多种,比如生存压力,情感问题,以及困扰着相当一部分人的职场焦虑.今天这篇关于“职场迷茫”的 ...

  4. 1.5 Scipy:高级科学计算

    sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&am ...

  5. div 当高度较小时指定高度,当高度较大时自适应

    在该元素或标签的样式中加入:{min-height:500px;height:auto;},其中min-height:是最小高度,auto是自适应内容.

  6. logstash 收集 IIS 日志实践

    IIS日志示例: 2017-02-20 00:55:40 127.0.0.1 GET /MkWebAPI/swagger/ui/index - 80 - 127.0.0.1 Mozilla/5.0+( ...

  7. 使用HttpClient4来构建Spring RestTemplate

    Spring RestTemplate简单说明 现在REST服务已经很普及了,在我们的程序中,经常会需要调用REST API,这时候会有很多选择,原始一点的JDK自带的,再进一步点使用HttpClie ...

  8. 【转载】iPhone系统概览

    iPhone OS OverviewiPhone系统概览iPhone OS comprises the operating system and technologies that you use t ...

  9. 【洛谷 P3191】 [HNOI2007]紧急疏散EVACUATE(二分答案,最大流)

    题目链接 sb错误调了3hour+.. bfs预处理出每个\(.\)到每个\(D\)的最短距离. 二分时间\(t\),把每个\(D\)拆成\(t\)个点,这\(t\)个点两两连边,流量\(INF\)表 ...

  10. 实现字符串检索strstr函数、字符串长度strlen函数、字符串拷贝strcpy函数

    #include <stdio.h> #include <stdlib.h> #include <string.h> /* _Check_return_ _Ret_ ...