作为程序员这样的特殊物种来说,都掌握了一种特殊能力就是编程思想,逻辑比較慎重,可是有时候总会忽略到一些细节,比方我,一直以来总认为Singleton是设计模式里最简单的,不用太在意,然而就是由于这样的不在意在开发中吃亏了.真的too young to simple.

好不扯淡了,直入主题.

在代码的世界里发现有各种写法的单例,有人说单例有5种,6种,7种…

对于单例的分类这点必须规范下,首先这么多种的分类是依据什么来定义的,基准是什么?

否则怎么会有那么多写法.

因此归纳下来,从延迟载入运行效率的角度出发主要也就分为两种,饿汉顾名思义就是运行效率高,但缺乏延时载入,其它写法差点儿相同都是懒汉式的一个拓展,或者优化而演化出来的,以下请看代码.

开发中经常使用的单例-饿汉式

public class SingletonDemo1 {

    private static final SingletonDemo1 s1 = new SingletonDemo1();

    public static SingletonDemo1 getInstance() {
return s1;
} private SingletonDemo1() {
}
}

没错上面这块代码叫做单例-饿汉式,饿汉式一直以效率高而闻名于单例界,因此咋们开发中经常使用的单例模式也会选择他,简单而好用.

>

开发评价: ★★★★☆

延时载入: ★☆☆☆☆

运行效率: ★★★★★

耗时的蜗牛-懒汉式

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

hello world这个世界里都知道这样的单例基本不会去用,在

double check双重检查锁-懒汉式

这能够说是上面饿汉式的一个缩影,为什么这么说,由于他并不完美,仍然有bug.

public class SingletonDemo3 {
private static SingletonDemo3 s1; public static SingletonDemo3 getInstance() {
if (s1 == null) {
//这里使用了暂时变量
SingletonDemo3 instance;
synchronized (SingletonDemo3.class) {
instance = s1;
if (instance == null) {
synchronized (SingletonDemo3.class) {
if (instance == null) {
instance = new SingletonDemo3();
}
}
s1 = instance;
}
}
}
return s1;
}
}

这个方式主要是通过if推断非null实例,提高了运行的效率,不必每次getInstace都要进行synchronize,仅仅要第一次要同步,有没创建了不用.

可是为什么说这样的写法有bug?这个问题主要是java的jvm层内部模型引起的.简单点说就是instance引用的对象有可能还没有完毕初始化完就直接返回该实例过去,在jdk1.5后这个问题才得到了优化,这不多说,能够看看这篇博文讲得不错.

详情见

当然也有了一些解决方法

  • 使用volatile关键字解决双重检查锁定的bug,对于volatile关键字就是Java中提供的另一种解决可见性和有序性问题的方案.
public class SafeDoubleCheckedLocking {
//加入了volatile关键字
private volatile static Instance instance; public static Instance getInstance() {
if (instance == null) {
synchronized (SafeDoubleCheckedLocking.class) {
if (instance == null)
instance = new Instance();//instance为volatile。如今没问题了
}
}
return instance;
}
}

>

开发评价: ★★★☆☆

延时载入: ★★★☆☆

运行效率: ★★★☆☆

推荐使用的静态内部类-懒汉式

public class SingletonDemo4 {

    //通过静态内部类的方式来实例化对象
private static class InnerSingleton {
private static final SingletonDemo4 instance = new SingletonDemo4();
} public static SingletonDemo4 getInstance() {
return InnerSingleton.instance;
} private SingletonDemo4() {
}
}

这周方式是利用了类载入的一些特性,在classloder的机制中,初始化instance时仅仅有一个线程,并且这样的方式另一个优点就是起到了延时载入的效果,当SingletonDemo4被载入了,可是内部类InnerSingleton并不会被载入,由于InnerSingleton没有主动使用,仅仅有通过调用getInstance方法时才会去载入InnerSingleton类,进而实例private static final SingletonDemo4 instance = new SingletonDemo4();

因此这样的巧妙的方式比起双重检查锁来说,安全来又高效了些.

>

开发评价: ★★★★☆

延时载入: ★★★★☆

运行效率: ★★★★☆

推荐使用的枚举-饿汉式

public enum SingletonDemo5 {

    //枚举元素本身就是一个单例(名字能够任意定义);
INSTANCE; //能够做一些单例的初始化操作
public void singletonOperation() {
}
}

这样的方式事实上非常帅,可是在实际开发中非常少人使用过,这点有点奇怪,首先enum本身就是一个单例,并且枚举另一个特性,能够避免放序列化和反射破解单例问题,经理再也不用操心单例安全了,可能是1.5才有enum的原因吧,假设项目适合的话能够试下这样的单例.

>

开发评价: ★★★★☆

延时载入: ★★★★☆

运行效率: ★★★★☆

总结一下:

对于以下的单例总的来说各有各的优点,至于开发中使用哪个能够依据你的业务需求来选择.

  • 饿汉

    • 标准饿汉 (安全防护方面 枚举单例更优于标准饿汉)

      线程安全,高效,不能够懒载入
    • 枚举单例

      线程安全,高效,不能够懒载入(天然避免反射与反序列化)

  • 懒汉 (效率方面 静态内部类更优于标准懒汉)
    • 标准懒汉

      线程安全,低效,能够懒载入
    • 双重检測(不推荐,有bug)

      线程安全,低效,能够懒载入
    • 静态内部类

      线程安全,低效,能够懒载入

对于单例的安全性问题,能够继续你那帅气的阅读姿势,java中你的单例是不是一直在裸奔

java中你确定用对单例了吗?的更多相关文章

  1. 如何使用双重检查锁定在 Java 中创建线程安全的单例?

    这个 Java 问题也常被问: 什么是线程安全的单例,你怎么创建它.好吧,在Java 5之前的版本, 使用双重检查锁定创建单例 Singleton 时,如果多个线程试图同时创建 Singleton 实 ...

  2. Java中反射和Unsafe破坏单例设计模式

    有如下单例模式设计代码: class Singleton { private String info = "HELLO SHIT"; private static Singleto ...

  3. JAVA之旅(六)——单例设计模式,继承extends,聚集关系,子父类变量关系,super,覆盖

    JAVA之旅(六)--单例设计模式,继承extends,聚集关系,子父类变量关系,super,覆盖 java也越来越深入了,大家加油吧!咱们一步步来 一.单例设计模式 什么是设计模式? JAVA当中有 ...

  4. Unity3D中可中途释放的单例

    Unity3D中可中途释放的单例 使用静态类,静态变量的坏处是从程序加载后就一直占用内存,想要释放比较麻烦,可是之前使用的单例,没有提供释放的方法,那是不是也同静态的一样直到程序结束菜释放?那单例的好 ...

  5. Effective java 第2版 - 笔记(01) 单例(Singleton)的枚举(enum)实现

    直接上代码: public enum Boss { INSTANCE; private String name; public void doSomeThing() { System.out.prin ...

  6. java笔记之静态修饰附和单例设计模式

     第六天笔记 静态修饰符static: 一.static修饰成员变量: static用来修饰成员变量叫静态成员变量,没有static修饰的成员变量叫非静态成员变量 静态成员的访问方式: (1)   用 ...

  7. 【Java】设计模型-五种单例模型

    一. 什么是单例模式 只需要某个类同时保留一个对象,不希望有更多对象,此时,我们则应考虑单例模式的设计. 单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在. 单例模式有很多好处,它能够 ...

  8. Effective Java - 构造器私有、枚举和单例

    目录 饿汉式单例 静态常量 静态代码块 懒汉式单例 尝试加锁 同步代码块 双重检查 静态内部类单例 枚举单例 Singleton 是指仅仅被实例化一次的类.Singleton代表了无状态的对象像是方法 ...

  9. C#中的简单工厂和单例

    下面首先来说说简单工厂 举个例子: 首先是父类 public abstract class Pizza { public abstract string Info(); } } 子类 public c ...

随机推荐

  1. Debug时检测到Loaderlock的解决办法

    昨天遇到了Loaderlock的问题. 出错信息为:检测到LoaderLock,正试图在OS加载程序锁内执行托管代码,不要尝试在DllMain或映像初始化函数内运行托管代码,这样会导致应用程序挂起. ...

  2. POJ 3368 Frequent values (基础RMQ)

    Frequent values Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 14742   Accepted: 5354 ...

  3. DB2数据源在Spring环境中的配置

    简单记录一下,以备不时之需. DB2的java驱动包可以在这里下载:http://pan.baidu.com/s/1gOoEJ DB2数据源的配置如下,粗体字部分是需要根据实际情况修改的: <b ...

  4. hadoop2.2.0_hbase0.96_zookeeper3.4.5全分布式安装文档下载

    本文档主要内容有: 1.hadoop 2.2.0 集群安装与部署 2.HBase 0.96 集群安装与部署 3.Zookeeper 3.4.5集群安装部署 备注:安装文档可能有所遗漏,后续将持续更新. ...

  5. 基于Mongodb进行分布式数据存储

    http://blog.csdn.net/daizhj/article/details/5868360 注:本文是研究Mongodb分布式数据存储的副产品,通过本文的相关步骤可以将一个大表中的数据分布 ...

  6. Discuz常见大问题-如何在自定义页面使用首页四格

    根据要求把majianjun文件夹放到指定目录 在DIY模式下点击保存后面的小按钮,然后导入XML文件 默认是采集所有版块的数据,你可以保存之后再次DIY,然后设置数据来源和设置标题等信息. 需要注意 ...

  7. 如何使用Replace Pioneer批量查找和替换并提取指定字符串

    1 我们查看源代码之后获得的网页文件如下图所示,一般都是href="/p-286018571.html"我们只要能提取到所有的"/p-XXXXXXXX.html" ...

  8. ADS ARM 汇编和GNU ARM汇编

    Linux/Unix内核源代码用的编译器是GCC,而GCC采用的是AT&T的汇编格式,这与ADS下使用的汇编格式是不同的. 两种汇编格式的部分对比如下: GNU ARM汇编 ADS ARM汇编 ...

  9. 【shell】正则表达式

    当一个文件或命令输出中抽取或过滤文本时,可以使用正则表达式(RE),正则表达式是一些特殊或很不特殊的字符串模式的集合. 在Linux中grep.awk.sed均可解释正则 1.基本元字符集及其定义 ^ ...

  10. 14、Java中用浮点型数据Float和Double进行精确计算时的精度问题

    一.浮点计算中发生精度丢失 大概很多有编程经验的朋友都对这个问题不陌生了:无论你使用的是什么编程语言,在使用浮点型数据进行精确计算时,你都有可能遇到计算结果出错的情况.来看下面的例子. // 这是一个 ...