设计模式学习--Singleton

What

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

Why

Singletion是我比较熟悉的设计模式之一,在日常的开发过程当中,也曾几回用到,它主要适用于以下场景:
一、当类只能有一个实例并且客户能够从一个众所周知的访问点访问它时。
二、当这个惟一实例应该是经过子类可扩展的,而且客户应该无需更改代码就能使用一个扩展的实例时。
在系统设计中,在涉及系统资源的管理时,每每会被设计成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实现

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

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以上,下面是以上示例的使用枚举的实现spa

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的很是好的方法。

相关文章
相关标签/搜索