What

Singleton:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

Why

Singletion是我比较熟悉的设计模式之一,在平常的开发过程中,也曾几次用到,它主要适用于如下场景:
1、当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
2、当这个唯一实例应该是通过子类可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
在系统设计中,在涉及系统资源的管理时,往往会被设计成Singletion模式,比如缓存、日志对象、线程池、对话框等等。

How

假设如下场景:一个简单的线程池,需要实现增加线程以及获取单个线程的功能。显然这个线程池对象是一个Singletion对象。
简单的实现代码如下:

public class ThreadPool {

    private List<Runnable> threads=new ArrayList<Runnable>();

    private static ThreadPool threadPool=null;

    private ThreadPool(){

    }

    public static ThreadPool getInstance(){
if(threadPool==null){
threadPool=new ThreadPool();
}
return threadPool;
} public void add(Runnable thread){
System.out.append("add a thread!");
threads.add(thread);
}
}

客户端调用

        ThreadPool threadPool=ThreadPool.getInstance();
threadPool.add(new Thread());

以上代码类图如下:

Discuss

线程安全的Singleton实现

以上代码,实现的是一个学习意义上的版本,在实际生产中,在一些情况下会出现问题,在多线程情况下,如下代码会出现什么问题?

    public static ThreadPool getInstance(){
if(threadPool==null){
threadPool=new ThreadPool();
}
return threadPool;
}

在多线程条件下,当一个线程执行到new ThreadPool()但是还没返回给threadPool,这时thread=null,另一个线程也会进入if代码片段,这样就创建了两个threadPool,造成这个的原因就是这段代码是线程非安全的。
经过优化形成如下版本:

public static ThreadPool getInstance() {

        synchronized (ThreadPool.class) {
if (threadPool == null) {
threadPool = new ThreadPool();
}
}
return threadPool;
}

这个版本可以很好的解决上个版本的问题,在一个线程进入了synchronized代码块,另一个线程就会等待。但是仔细想想,如果对象已经创建,线程还是需要等待进入synchronized代码块才会知道threadPool!=null,这样会造成比较严重性能问题,再来一个版本

public static ThreadPool getInstance() {
if (threadPool == null) {
synchronized (ThreadPool.class) {
if (threadPool == null) {
threadPool = new ThreadPool();
}
}
}
return threadPool;
}

ok,这个版本看上去完美了,可以在生产中使用了。这是线程安全的实现。
以上代码还是可以通过一些办法在一个JVM中创建多个ThreadPool实例,想想是什么?对,可以通过反射的方式来,创建n多个实例,java的反射机制可以通过private的构造器创建实例。

使用枚举实现Singleton

Effectvie java的作者Joshua Bloch提出了一个可以绝对防止多次实例化,而且无偿的提供了序列化机制的方法,使用枚举实现Singleton,当然java版本需要在1.5以上,下面是以上示例的使用枚举的实现

public enum ThreadPool {

    Instance;

    private List<Runnable> threads=new ArrayList<Runnable>();

    public void add(Runnable thread){
System.out.append("add a thread!");
threads.add(thread);
}
}

客户端调用

 ThreadPool.Instance.add(new Thread());

可以看出使用枚举方式,代码比较简洁而且可以绝对防止多次实例化,是一个实现Singleton的非常好的方法。

设计模式学习--Singleton的更多相关文章

  1. python之路,Day24 常用设计模式学习

    python之路,Day24 常用设计模式学习   本节内容 设计模式介绍 设计模式分类 设计模式6大原则 1.设计模式介绍 设计模式(Design Patterns) --可复用面向对象软件的基础 ...

  2. Java设计模式学习记录-GoF设计模式概述

    前言 最近要开始学习设计模式了,以前是偶尔会看看设计模式的书或是在网上翻到了某种设计模式,就顺便看看,也没有仔细的学习过.前段时间看完了JVM的知识,然后就想着JVM那么费劲的东西都看完了,说明自己学 ...

  3. C#设计模式学习笔记-单例模式随笔

    最近学习 设计模式,从单例模式入手 啥是单例模式: 要实现一个单例类的话,首先,肯定是不能让用户自行生产的,那就是说明不能让用户new,所以,就必须把构造函数设置成为私有的 因为静态变量的生命周期跟整 ...

  4. C#设计模式学习笔记-单例模式(转)

    C#设计模式学习笔记-单例模式 http://www.cnblogs.com/xun126/archive/2011/03/09/1970807.html 最近在学设计模式,学到创建型模式的时候,碰到 ...

  5. C#大话设计模式学习总结

    如有雷同,不胜荣欣,如转载,请注明 C#大话设计模式学习总结 一.工厂模式 面向对象的三个特性:封装,继承和多态 1.封装 Class Operate { privatedouble _numberA ...

  6. Java设计模式学习笔记(五) 单例模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 使用单例模式的原因 以Windows任务管理器为例,在Windows系统中,任务管理器是唯 ...

  7. 设计模式学习系列6 原型模式(prototype)

    原型模式(prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.允许一个对象再创建另外一个新对象的时候根本无需知道任何创建细节,只需要请求圆形对象的copy函数皆可. 1 ...

  8. Java-马士兵设计模式学习笔记-总结

    <马士兵设计模式学习>学习了以下模式: 1.装饰者模式(例子:水管工,木工) 2.策略模式(例子:老师用职称比大小.学生用成绩比大小) 3.简单工厂模式(例子:VechileFactory ...

  9. Java设计模式学习资源汇总

    本文记录了Java设计模式学习书籍.教程资源.此分享会持续更新: 1. 设计模式书籍 在豆瓣上搜索了一把,发现设计模式贯穿了人类生活的方方面面.还是回到Java与程序设计来吧. 打算先归类,再浏览,从 ...

随机推荐

  1. http://jqweui.com/

    http://jqweui.com/ jQuery WeUI jQuery WeUI 是专为微信公众账号开发而设计的一个简洁而强大的UI库,包含全部WeUI官方的CSS组件,并且额外提供了大量的拓展组 ...

  2. Windows平台下tomcat 性能调优

    Tomcat 线程查看工具: https://blog.csdn.net/jrainbow/article/details/49026365 16G内存 Tomcat并发优化.内存配置.垃圾回收.宕机 ...

  3. C#-MVC开发微信应用(5)--自动应答系统-自动回复机器人

    前几篇已经介绍菜单和有回复信息操作,下面我们就结合snf微信端管理页面,看一下什么才是自动应答系统. 定制的服务 对于微信服务号来说,最主要的功能是提供更好的服务.用户更方便的操作,以及更快的反馈响应 ...

  4. iOS画折线图

    代码例子效果:  下载地址:http://download.csdn.net/detail/qqmcy/6983187 LineChartViewDemo.h #import <UIKit/UI ...

  5. MySql实现sequence功能的代码

    使用函数创建自增序列管理表(批量使用自增表,设置初始值,自增幅度) 第一步:创建Sequence管理表 sequence DROP TABLE IF EXISTS sequence; CREATE T ...

  6. java this 子类调父类,父类再调用子类已覆盖的方法及属性(又一次理解)

    之前一直以为 this关键字 是指调用者对象,但是这次才真正理解,this代表当前对象,但是指向调用者对象,其实就是多态的用法,如下所示:B 继承了 A,在B 中调用A类的方法,在A 中用this 访 ...

  7. pandas 学习总结

    pandas  学习总结 作者:csj 更新时间:2018.04.02 shenzhen email:59888745@qq.com home: http://www.cnblogs.com/csj0 ...

  8. java 虚拟机设置 Xms Xmx PermSize MaxPermSize

    Eclipse崩溃,错误提示:MyEclipse has detected that less than 5% of the 64MB of Perm Gen (Non-heap memory) sp ...

  9. visio操作

    1.上下标:选中要成为上标的文字,ctrl+shift+"=" 选中要成为下标的文字,ctrl+"="

  10. MinGW 使用 mintty 终端替代默认终端以解决界面上复制与粘贴的问题

    使用了一段时间的 cygwin,挺开心的,又尝试了下同类工具 Msys + MinGW,安装好之后发现它居然使用默认的 cmd 作为终端,界面输出内容的复制与粘贴极其不便,我记得 Cygwin 使用的 ...