1.//懒汉模式
//天生线程不安全,但是效率高
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getSingleton(){
if(singleton==null){
singleton=new Singleton();
System.out.println("实例化Singleton");
}
return singleton;
} } public class Test {
public static void main(String[] args) {
MyThread myThread1=new MyThread();
MyThread myThread2=new MyThread();
MyThread myThread3=new MyThread();
myThread1.start();
myThread2.start();
myThread3.start();
}
//因为继承Thread每次都会新创建一个任务,所以可以达到效果,而使用Runnable不能够达到效果
public static class MyThread extends Thread{
int count=0;
@Override
public void run() {
while(count<100){
count++;
Singleton.getSingleton();
}
}
}
}

此程序输出的结果为:

实例化Singleton
实例化Singleton

说明此时实例化了两个Singleton,线程不安全!

2.在上面做一点改动

//改良版懒汉模式
//线程安全,但是效率低
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getSingleton(){
if(singleton==null){
singleton=new Singleton();
System.out.println("实例化Singleton");
}
return singleton;
} } public class Test {
public static void main(String[] args) {
MyThread myThread1=new MyThread();
MyThread myThread2=new MyThread();
MyThread myThread3=new MyThread();
myThread1.start();
myThread2.start();
myThread3.start();
}
//因为继承Thread每次都会新创建一个任务,所以可以达到效果,而使用Runnable不能够达到效果
public static class MyThread extends Thread{
int count=0;
@Override
public void run() {
while(count<100){
count++;
Singleton.getSingleton();
}
}
}
}

3.饿汉模式

//饿汉模式
//线程安全,但每次加载类的时候都会实例化,若存在大量的此种单例模式,则会实例化很多无用实例
public class Singleton {
private static Singleton singleton=new Singleton();
private Singleton() {}
public static Singleton getSingleton(){
System.out.println("Singleton");
return singleton;
}
}

4.饿汉模式

//饿汉模式,和第三种一样,只不过换个写法

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

5.静态内部类

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

6.枚举类(推荐)

public enum Singleton { singleton; //此处可以是任何方法 public void out(){ System.out.println(singleton.hashCode()); } }

使用枚举类作为单例的好处有三点:1.天生线程安全(因为枚举类是线程安全的)2.反序列化后不会创建多个实例 3.防反射攻击(因为枚举类是abstract),反编译如下

public abstract class Singleton extends Enum
{ private Singleton(String s, int i)
{
super(s, i);
} protected abstract void read(); protected abstract void write(); public static Singleton[] values()
{
Singleton asingleton[];
int i;
Singleton asingleton1[];
System.arraycopy(asingleton = ENUM$VALUES, 0, asingleton1 = new Singleton[i = asingleton.length], 0, i);
return asingleton1;
} public static Singleton valueOf(String s)
{
return (Singleton)Enum.valueOf(singleton/Singleton, s);
} Singleton(String s, int i, Singleton singleton)
{
this(s, i);
} public static final Singleton INSTANCE;
private static final Singleton ENUM$VALUES[]; static
{
INSTANCE = new Singleton("INSTANCE", 0) { protected void read()
{
System.out.println("read");
} protected void write()
{
System.out.println("write");
} };
ENUM$VALUES = (new Singleton[] {
INSTANCE
});
}
}

7.双重检查锁定

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;
}
}

总结

有两个问题需要注意:

1.如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。

2.如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。

对第一个问题修复的办法是:

  1. private static Class getClass(String classname)
  2. throws ClassNotFoundException {
  3. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  4. if(classLoader == null)
  5. classLoader = Singleton.class.getClassLoader();
  6. return (classLoader.loadClass(classname));
  7. }
  8. }

对第二个问题修复的办法是:

  1. public class Singleton implements java.io.Serializable {
  2. public static Singleton INSTANCE = new Singleton();
  3. protected Singleton() {
  4. }
  5. private Object readResolve() {
  6. return INSTANCE;
  7. }
  8. }

更多详情可以访问http://cantellow.iteye.com/blog/838473;

在此感谢这篇文章给我的启示。

Singleton的更多相关文章

  1. 23种设计模式--单例模式-Singleton

    一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...

  2. 设计模式之单例模式(Singleton)

    设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...

  3. PHP设计模式(四)单例模式(Singleton For PHP)

    今天讲单例设计模式,这种设计模式和工厂模式一样,用的非常非常多,同时单例模式比较容易的一种设计模式. 一.什么是单例设计模式 单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对 ...

  4. The Java Enum: A Singleton Pattern [reproduced]

    The singleton pattern restricts the instantiation of a class to one object. In Java, to enforce this ...

  5. 最适合作为Java基础面试题之Singleton模式

    看似只是最简单的一种设计模式,可细细挖掘,static.synchronized.volatile关键字.内部类.对象克隆.序列化.枚举类型.反射和类加载机制等基础却又不易理解透彻的Java知识纷纷呼 ...

  6. 每天一个设计模式-4 单例模式(Singleton)

    每天一个设计模式-4 单例模式(Singleton) 1.实际生活的例子 有一天,你的自行车的某个螺丝钉松了,修车铺离你家比较远,而附近的五金店有卖扳手:因此,你决定去五金店买一个扳手,自己把螺丝钉固 ...

  7. Qt 中使用Singleton模式需小心

    在qt中,使用Singleton模式时一定要小心.因为Singleton模式中使用的是静态对象,静态对象是直到程序结束才被释放的,然而,一旦把该静态对象纳入了Qt的父子对象体系,就会导致不明确的行为. ...

  8. 设计模式之单例模式——Singleton

                        设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有 ...

  9. C#面向对象设计模式纵横谈——2.Singleton 单件(创建型模式)

    一:模式分类 从目的来看: 创建型(Creational)模式:负责对象创建. 结构型(Structural)模式:处理类与对象间的组合. 行为型(Behavioral)模式:类与对象交互中的职责分配 ...

  10. 【白话设计模式四】单例模式(Singleton)

    转自:https://my.oschina.net/xianggao/blog/616385 0 系列目录 白话设计模式 工厂模式 单例模式 [白话设计模式一]简单工厂模式(Simple Factor ...

随机推荐

  1. 《Entity Framework 6 Recipes》中文翻译系列 (8) -----第二章 实体数据建模基础之继承关系映射TPT

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 2-8 Table per Type Inheritance 建模 问题 你有这样一 ...

  2. MySQL_01之MySQL数据库基础

    1.通过SQL(结构化查询语言)操作数据库: DDL:数据定义语言,创建库,创建表,选择: DML:数据操作语言,完成数据增删改: DQL:数据查询语言,完成数据查询: DCL:数据控制语言,授权.回 ...

  3. iOS中通讯录的开发

    通讯录开发主要是获取用户手机中的联系人,进而可以在应用中添加好友 一 .如何访问通讯录 (1)在iOS9之前,有两个框架可以访问用户的通讯录 AddressBookUI.framework: 提供了联 ...

  4. 09 web开发高级应用(1)

    - 1 <base> 标签用法 ```base: 为页面上的所有链接规定默认地址或默认目标target: 跳转到的目标页 <base target=_blank> <!- ...

  5. 我为NET狂-----大前端专帖

    http://dnt.dkill.net/Article/Detail/321 本来前端的东西是不想开个专贴的,这样网友容易产生依赖,前端的东西看看书,平时仿照几个网站,遇到问题再调调增加点经验,基本 ...

  6. OpenCascade Chinese Text Rendering

    OpenCascade Chinese Text Rendering eryar@163.com Abstract. OpenCascade uses advanced text rendering ...

  7. Util应用程序框架公共操作类(三):数据类型转换公共操作类(扩展篇)

    上一篇以TDD方式介绍了数据类型转换公共操作类的开发,并提供了单元测试和实现代码,本文将演示通过扩展方法来增强公共操作类,以便调用时更加简化. 下面以字符串转换为List<Guid>为例进 ...

  8. Hawk: 20分钟无编程抓取大众点评17万数据

    1. 主角出场:Hawk介绍 Hawk是沙漠之鹰开发的一款数据抓取和清洗工具,目前已经在Github开源.详细介绍可参考:http://www.cnblogs.com/buptzym/p/545419 ...

  9. geotrellis使用(十一)实现空间数据库栅格化以及根据属性字段进行赋值

    Geotrellis系列文章链接地址http://www.cnblogs.com/shoufengwei/p/5619419.html 目录 前言 安装空间数据库 空间数据库栅格化 根据属性字段进行赋 ...

  10. DOM 节点的克隆与删除

    无奈的开头 关于DOM节点操作,如果仅仅是根据标准API来操作,那是最简单不过的了.但是现实中却哪有这么容易的问题让我们解决,其实不仅仅是节点的克隆与删除,节点的添加也是如此,而且添加节点需要考虑的情 ...