设计模式学习--Singleton

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,布布扣,bubuko.com

时间: 2024-11-19 22:22:17

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

设计模式学习--Singleton泛型类

/// <summary> /// Singleton泛型类 /// </summary> /// <typeparam name="T"></typeparam> public sealed class Singleton<T> where T : new() { private static T instance = new T(); private static object lockHelper = new objec

java/android 设计模式学习笔记(一)---单例模式

前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使用的时候也会有一些坑. PS:对技术感兴趣的同鞋加群544645972一起交流 设计模式总目录 java/android 设计模式学习笔记目录 特点 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 单例模式的使用很广泛,比如:线程池(threadpool).缓存(cache).对

java/android 设计模式学习笔记(9)---代理模式

这篇博客我们来介绍一下代理模式(Proxy Pattern),代理模式也成为委托模式,是一个非常重要的设计模式,不少设计模式也都会有代理模式的影子.代理在我们日常生活中也很常见,比如上网时连接的代理服务器地址,更比如我们平时租房子,将找房子的过程代理给中介等等,都是代理模式在日常生活中的使用例子. 代理模式中的代理对象能够连接任何事物:一个网络连接,一个占用很多内存的大对象,一个文件,或者是一些复制起来代价很高甚至根本不可能复制的一些资源.总之,代理是一个由客户端调用去访问幕后真正服务的包装对象

设计模式学习02—工厂模式

1.动机与定义 我们在程序中使用一个对象时,需要new一下,如果需要设置其他值就再初始化一下.比如我要使用一个按钮,手动new一个矩形按钮,然后初始化一些值,如显示文字,背景色等. // 矩形按钮 IButton btn = new RecButton(); // 初始化其他值 btn.setText("提交"); btn.setBackgroundColor("#00aaff"); // 其他初始化省略 // 圆形按钮 IButton btn2 = new Rou

【我的设计模式学习】单例模式

单例模式大概是最直观的一种设计模式了.尽管直观却不简单. 数学与逻辑学中,singleton定义为"有且仅有一个元素的集合".单例模式可以如下定义:"一个类有且仅有一个实例,并且自行实例化向整个系统提供". 我比较喜欢Design Patterns 一书中的描述"保证一个类仅有一个实例,并提供一个访问它的全局访问点". 单例模式的特点 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例

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

python之路,Day24 常用设计模式学习 本节内容 设计模式介绍 设计模式分类 设计模式6大原则 1.设计模式介绍 设计模式(Design Patterns) --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一

设计模式学习01—单例模式

一.动机与定义 系统中有些资源只能有一个,或者一个就够,多个浪费.例如一个系统只能有一个窗口管理器或文件系统.一个系统只能有一个计时器或序号生成器.web系统只能有一个页面计数器等等.此时,最好就需要把这些资源设置成有且仅有一个实例. 代码中也就是如何保证一个类只有一个实例并且这个实例能够被访问呢?只有一个实例的就意味着不能让其他类来实例化,也就是只能自己实例化自己.能够被访问也就意味着自身要对外提供全局方法来获取到这个实例,这就是单例模式. 单例模式定义:确保某一个类只有一个实例,而且自行实例

设计模式学习总结

本文是对各处设计模式示例的总结概括和简化,主要参考 http://blog.csdn.net/zhangerqing/article/details/8194653 直接看本文估计比较枯燥无聊,因为没图~~??,建议对设计模式有兴趣的先看看上面的博文,或者基础比较好可直接移到最底下看下我的各模式一句话概括总结,有什么意见建议欢迎提出~~~~~~~~~~ 总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式.结构型模式,共七种:适配器模式.装饰

java/android 设计模式学习笔记(14)---外观模式

这篇博客来介绍外观模式(Facade Pattern),外观模式也称为门面模式,它在开发过程中运用频率非常高,尤其是第三方 SDK 基本很大概率都会使用外观模式.通过一个外观类使得整个子系统只有一个统一的高层的接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节.当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块.ImageLoader 模块等.其实我们在开发过程中可能已经使用过很多次外观模式,只是没有从理论层面去了解它. 转载请注明出处:http://bl