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. hive中 regexp_replace的用法,替换特殊字符问题

    数据仓库中有的字段不合格,有特殊字符,比如换行符. poi_name \n19013 \n12013 怎么把换行符替换掉呢? https://cwiki.apache.org/confluence/d ...

  2. ASP.NET Core入门系列教程

    微软把这个新的框架叫:Razor Pages,以下文中我们将频繁提及—Razor Pages. 项目目录结构 wwwroot静态资源文件夹首先,Razor Pages项目中多了一个wwwroot的文件 ...

  3. [Python设计模式] 第10章 怎么出试卷?——模版方法模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目 小时候数学老师的随堂测验,都是老师在黑板上写题目,学生在下边抄,然后再做题 ...

  4. MDX Cookbook 05 - 条件过滤 FILTER-COUNT 与 SUM-IIF 实现

    下面的这个查询返回每个财月的 Customer Count 和 基于上个月比较的 Growth in Customer Base 的记录,Slicer 是 Mountain bikes. SELECT ...

  5. js 引擎 和 html 渲染引擎

  6. Android学习笔记(五一):服务Service(上)- IntentService

    转自 http://blog.csdn.net/flowingflying/article/details/7616333 对于需要长期运行,例如播放音乐.长期和服务器的连接,即使已不是屏幕当前的ac ...

  7. 【Linux】使用w命令和uptime命令查看系统负载

    在Linux系统中查询系统CPU和内存的负载(使用率)时,我们通常习惯于使用top.atop或者ps,这篇文章将要给大家介绍如何使用w命令和uptime命令来查看系统的负载情况,对于uptime命令, ...

  8. Git教程学习(三)

    主要命令: $ git checkout -- readme.txt #使用暂存区或版本库中最新的版本替换工作区版本 $ git reset HEAD readme.txt # 撤消指定文件的add操 ...

  9. qeephp 记录下

    百度百科: https://baike.baidu.com/item/qeephp/8328612?fr=aladdin 官方地址: http://www.qeephp.cn/app/index.ph ...

  10. C#sql语句

    SQL语句大全删除数据库 drop database databasename SQL语句大全备份 --- 创建备份数据的 device USE master EXEC sp_addumpdevice ...