单例模式大概是最直观的一种设计模式了,尽管直观却不简单。

数学与逻辑学中,singleton定义为“有且仅有一个元素的集合”,

单例模式可以如下定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供”。

我比较喜欢Design Patterns 一书中的描述"保证一个类仅有一个实例,并提供一个访问它的全局访问点"。

单例模式的特点

1.单例类只能有一个实例

2.单例类必须自己自己创建自己的唯一实例

3.例类必须给所有其他对象提供这一实例

单例模式的经典实现

实现单例,可以将类的构造方法限定为private,避免在外部实例化,然后在类中提供一个静态的实例并能够返回给使用者,
在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance方法访问。

public class Singleton {

/**
* classic singleton
* realize lazy loaded 添加判断uniqueInstance是否初始化,实现了使用时才进行加载
*/
private static Singleton uniqueInstance=null; private Singleton(){
//Exits only to defeat instantiation
}
public static Singleton getInstance(){
if(uniqueInstance==null){
uniqueInstance =new Singleton();
}
return uniqueInstance;
}
}

线程安全的实现  

经典的实现方法并没有考虑多线程的环境,试想存在两个线程A和B,
同时调用getInstance方法,线程A检查uniqueInstance是null,开始创建实例;
同时线程B检测到uniqueInstance是null,于是线程A/B各自创建了对象。

解决这个问题最简单的方法是加锁,为getInstance的静态方法添加synchronized关键字,
但是考虑到Synchronized同步锁的性能较低,可以调整Synchronized添加(加锁)的位置。

public class SingletonSafed {

	/**
* 要在于instance = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。
* 给 instance 分配内存
* 调用 Singleton 的构造函数来初始化成员变量
* 将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)
* 使用volatile禁止指令重排序优化
*/
//在Java里所有引用类型的静态以及实例成员,没有显式地初始化的,都会被设为null
private volatile static SingletonSafed uniqueInstance; private SingletonSafed(){
//私有的构造方法,防止外部实例化
} //注意设置为静态方法
public static SingletonSafed getInstance(){
if(uniqueInstance== null){
/**
* 同步块加锁。双重检查锁,因为会有两次检查 instance == null,一次是在同步块外,一次是在同步块内。
* 为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例。
*/
synchronized(SingletonSafed.class){
if(uniqueInstance== null){
uniqueInstance= new SingletonSafed();
} }
}
return uniqueInstance;
}
}

  

饿汉式 懒汉式和登记式

另外,一些文档会提到单例模式的三种形式(懒汉式,饿汉式,登记式),
其实饿汉式和懒汉式主要是线程安全的区别,同时懒汉式是延迟加载,
在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,例如下面代码:

//饿汉式单例类.在类初始化时,已经自行实例化
public class Singleton1 {
//私有的默认构造子
private Singleton1() {}
//已经自行实例化
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
return single;
}
}

懒汉式单例:

//懒汉式单例类.在第一次调用的时候实例化
public class Singleton2 {
//私有的默认构造子
private Singleton2() {}
//注意,这里没有final
private static Singleton2 single=null;
//静态工厂方法
public synchronized static Singleton2 getInstance() {
if (single == null) {
single = new Singleton2();
}
return single;
}
}

好文书签

如何正确地写出单例模式

聊聊并发(二)——Java SE1.6中的Synchronized

创建型模式之Singleton模式的更多相关文章

  1. Java设计模式(2)单态模式(Singleton模式)

    定义:Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在. 在很多操作中,比如建立目录 数据库连接都需要这样的单线程操作. 还有,singleton能够被状态化 ...

  2. 【python设计模式-创建型】工厂方法模式

    工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻 ...

  3. JAVA设计模式 3【创建型】理解工厂模式与抽象工厂模式

    上一节我们已经学习了原型模式,稍微复习一下:通过重写Object 类的clone() 方法实现浅克隆,浅克隆也要实现Cloneable 标记接口.而深克隆则是将对象通过序列化和反序列化 的方式进行创建 ...

  4. 【创建型】Abstract Factory模式 & Factory Method模式

    本文主要介绍简单工厂模式与抽象工厂模式.以下如有叙述不当之处,欢迎批评指正,欢迎交流探讨. 一:简单工厂模式 在23种设计模式中,简单工厂模式其实是不在列的,但理解该模式对于抽象工厂模式的思想理解是有 ...

  5. 创建型设计模式之原型模式(Prototype)

    结构   意图 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 适用性 当要实例化的类是在运行时刻指定时,例如,通过动态装载:或者 为了避免创建一个与产品类层次平行的工厂类层次时:或 ...

  6. 创建型设计模式之建造者模式(Builder)

    结构 意图 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 适用性 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时. 当构造过程必须允许被构造的对象有不 ...

  7. 创建型设计模式之工厂模式(Abstract Factory)

    结构            意图         提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 适用性     一个系统要独立于它的产品的创建.组合和表示时. 一个系统要由多个 ...

  8. JAVA设计模式 4【创建型】理解建造者模式

    Hello,又是拖了几天更,实在是忙的要死,有时候忙累了,真的就是倒头睡的那种,刚好今天闲下来了.今天来更新一篇建造者模式. 其实建造者模式,我们已经在上一节已经有了解过了.只不过是上一节没有提到这样 ...

  9. PYTHON设计模式,创建型之工厂方法模式

    我感觉和上一个差不多,可能不要动最要的地方吧... #!/usr/bin/evn python #coding:utf8 class Pizza(object): def prepare(self, ...

随机推荐

  1. 《项目经验》--后台一般处理程序向前台JS文件传递JSON,JS解析JSON,将数据显示在界面--显示在DropDownList 或 显示在动态创建的table中

    http://blog.csdn.net/mazhaojuan/article/details/8599167 先看一下我要实现的功能界面: 这篇文章主要介绍:后台一般处理程序把从数据库查找的数据,转 ...

  2. AspectJ AOP学习基础

    一.切入点表达式 1.execution:匹配方法的执行 格式:execution(修饰符 返回值类型 包.类.方法(参数) throw 异常) 1.1修饰符,表示方法的修饰符,一般省略. 1.2返回 ...

  3. AppCompat学习(1)-AppCompatSpinner

    andriod中的spinner控件一共有两个,一个是本身的Spinner,一个是android.support.v7.widget.AppCompatSpinner. 两者的区别在于v7内的Spin ...

  4. webexam项目杂记

    sql 语句 数据库 本身 有数据类型的区分,对于mysql的字符串默认的用单引号''来表示,因此,整个sql 语句就要用双引号来括. 如: $sql = "SELECT * FROM us ...

  5. Linux下链接mysql数据库的命令

    一.MySQL 连接本地数据库,用户名为“root”,密码“123”(注意:“-p”和“123” 之间不能有空格) C:\>mysql -h localhost -u root -p123 二. ...

  6. 幼谈苹果新开发语言:Swift和苹果的用心

    今天是个值得纪念的日子:因为苹果的WWDC大会.苹果的每次WWDC(全球开发者大会)举行都让我们像打了肾上腺素这么兴奋.幸福.惊叹.震撼.深思. 今年也不例外,最关键的是苹果带来了它的一门新开发语言: ...

  7. 繁华模拟赛 ljw搭积木

    #include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...

  8. Don't make me think 摘录与读后感

    别让我思考 ——Krug可用性第一定律 点击多少次都没关系,只要每次点击都是无需思考,明确无误的选择.——Krug可用性第二定律 去掉每个页面上一般的文字, 然后把剩下的文字再去掉一半 ——Krug可 ...

  9. MBProgressHUD使用

    //方式1.直接在View上show HUD = [[MBProgressHUD showHUDAddedTo:self.view animated:YES] retain]; HUD.delegat ...

  10. 今天逛VC驿站 的收获

    1.C++ 如何定义一个定长字符串, 若不足位数,就补字符串"0"? eg: CString str1 = “123”;不足20位,前面补“0”,实现效果为“00000000000 ...