设计模式——单例模式
2017-01-17 13:27
232 查看
作为开发者的我们,想必设计模式对大家来说并不陌生,设计模式共有23种,分别是:工厂方法(FactoryMethod)、抽象工厂(AbstractFactory) 、建造者模式(Builder)、单态模式(Singleton)、 原型模式(Prototype)、 适配器模式(Adapter)、桥接模式(Bridge) 、组合模式(Composite) 、装饰模式(Decorator)、外观模式(Facade)、 享元模式(Flyweight)、代理模式(Proxy)、责任链模式(Chain of Responsibility)、 命令模式(Command)、 解释器模式(Interpreter) 、迭代器模式(Iterator)、中介者模式(Mediator)、备忘录模式(Memento)、观察者模式(Observer)、状态模式(State)、策略模式(Strategy) 、模板方法(TemplateMethod)、访问者模式(Visitor)。这23种设计模式又分为三类,分别是:创建型模式、结构型模式和行为型模式。创建型模式分别包含的是工厂方法(FactoryMethod)、抽象工厂(AbstractFactory) 、建造者模式(Builder)、单态模式(Singleton)、 原型模式(Prototype)。结构型模式分别包含的是: 适配器模式(Adapter)、桥接模式(Bridge) 、组合模式(Composite) 、装饰模式(Decorator)、外观模式(Facade)、 享元模式(Flyweight)、代理模式(Proxy)。行为型模式分别包含的是:责任链模式(Chain of Responsibility)、 命令模式(Command)、 解释器模式(Interpreter) 、迭代器模式(Iterator)、中介者模式(Mediator)、备忘录模式(Memento)、观察者模式(Observer)、状态模式(State)、策略模式(Strategy) 、模板方法(TemplateMethod)、访问者模式(Visitor)。
了解了以上还远远不够,下面我们就来了解一下23种设计模式之一的单例模式。单例模式对我们开发者来说是再熟悉不过了。单例模式又分为饿汉式(线程安全,调用效率高。但是不能延时加载)、懒汉式(线程安全,调用效率低。可以延时加载)、双重检测锁(由于此模式偶尔会出现问题,不建议使用)、静态内部类式(线程安全,调用效率高。可以延时加载)、枚举单例(线程安全,调用效率高。不能延时加载)。单例模式的优点是:减少系统开销。我们经常使用的是饿汉式和懒汉式这两种。我们先来说一下饿汉式,饿这个字我想大家都知道啥意思,举个例子:当你很饿的时候你会去挑选你喜欢的食物吗?当然不会。当你很饿的时候,恰好发现有一些食物,此时的你不管是否是自己喜欢的食物,只要能充饥你都会去吃的。饿汉式模式也是一样,不论是否使用,先创建一个实例再说。缺点就是如果只加载本类,而不去调用getSingleton()这个方法的话,将会造成资源的浪费。因为一开始上来不论分说的先创建实例,这样很容易造成资源浪费。
懒汉式则就不同了,懒汉式就好比你不是很饿,此时的你很困正在床上休息,不论旁边的人如何喊你吃东西,只要不是自己特别喜欢吃的,你都懒得起来去吃,当听到有你喜欢吃的东西的时候此时的你可能会去品尝一下。懒汉式就是这样,不调用就不实例化。虽然解决了资源的浪费,但是由于每次调用getSingleton() 时都要同步,造成并发效率特别低。也许有人会说我不会不加synchronized 这个关键字进行同步限制吗?但是这样做是不行的,如果并发量有点高的情况下容易造成多次实例化,比如说线程1和线程2调用了getSingleton()这个方法,当刚调用还没有来得及判断singleton是否为空是,此时线程1挂起了,然后当线程2执行到singleton = new Singleton2()时,线程2挂起,此时线程1又从刚刚挂起的地方执行,这样就导致被实例化了两次。如果加了synchronized 以后,即使线程1挂起,线程2也不会去执行,直到线程1执行完,线程2才会去执行。
双重检测锁,顾名思义就是多次检测,这个模式将同步内容放到if里面,这样做提高了执行效率,没有必要每次获取对象时都要进行同步,只有第一次才会同步,以后每次都不需要。由于编译器优化问题此模式不建议使用。
静态内部类模式,里面会用到final 这个关键字,static final 的作用就是防止被改变。这样获取到的空间地址永远是不会改变的,这样就会保证只有一个实例存在,而且是线程安全的。具备有高并发和延时加载的优势。
枚举单例,枚举本身就是单例,缺点就是没有延时加载。
基于以上五种单例模式我们应该如何选择呢?如果是单例对象,占用资源较少,而且又不需要延时加载的话枚举式好于饿汉式。如果是单例对象,占用资源较大,而且需要延时加载的话静态内部类好于懒汉式。单例模式就到此结束了,平时我们使用的Application里面就涉及有单例模式。
了解了以上还远远不够,下面我们就来了解一下23种设计模式之一的单例模式。单例模式对我们开发者来说是再熟悉不过了。单例模式又分为饿汉式(线程安全,调用效率高。但是不能延时加载)、懒汉式(线程安全,调用效率低。可以延时加载)、双重检测锁(由于此模式偶尔会出现问题,不建议使用)、静态内部类式(线程安全,调用效率高。可以延时加载)、枚举单例(线程安全,调用效率高。不能延时加载)。单例模式的优点是:减少系统开销。我们经常使用的是饿汉式和懒汉式这两种。我们先来说一下饿汉式,饿这个字我想大家都知道啥意思,举个例子:当你很饿的时候你会去挑选你喜欢的食物吗?当然不会。当你很饿的时候,恰好发现有一些食物,此时的你不管是否是自己喜欢的食物,只要能充饥你都会去吃的。饿汉式模式也是一样,不论是否使用,先创建一个实例再说。缺点就是如果只加载本类,而不去调用getSingleton()这个方法的话,将会造成资源的浪费。因为一开始上来不论分说的先创建实例,这样很容易造成资源浪费。
public class Singleton { private static Singleton singleton = new Singleton(); public Singleton() { } public static Singleton getSingleton() { return singleton; } }
懒汉式则就不同了,懒汉式就好比你不是很饿,此时的你很困正在床上休息,不论旁边的人如何喊你吃东西,只要不是自己特别喜欢吃的,你都懒得起来去吃,当听到有你喜欢吃的东西的时候此时的你可能会去品尝一下。懒汉式就是这样,不调用就不实例化。虽然解决了资源的浪费,但是由于每次调用getSingleton() 时都要同步,造成并发效率特别低。也许有人会说我不会不加synchronized 这个关键字进行同步限制吗?但是这样做是不行的,如果并发量有点高的情况下容易造成多次实例化,比如说线程1和线程2调用了getSingleton()这个方法,当刚调用还没有来得及判断singleton是否为空是,此时线程1挂起了,然后当线程2执行到singleton = new Singleton2()时,线程2挂起,此时线程1又从刚刚挂起的地方执行,这样就导致被实例化了两次。如果加了synchronized 以后,即使线程1挂起,线程2也不会去执行,直到线程1执行完,线程2才会去执行。
public class Singleton2 { private static Singleton2 singleton; public Singleton2() { } public static synchronized Singleton2 getSingleton() { if (singleton==null){ singleton = new Singleton2(); } return singleton; } }
双重检测锁,顾名思义就是多次检测,这个模式将同步内容放到if里面,这样做提高了执行效率,没有必要每次获取对象时都要进行同步,只有第一次才会同步,以后每次都不需要。由于编译器优化问题此模式不建议使用。
public class Singleton3 { private static Singleton3 singleton=null; public Singleton3() { } public static Singleton3 getSingleton() { if (singleton==null){ Singleton3 st; synchronized (Singleton3.class){ st = singleton; if (st==null){ synchronized (Singleton3.class){ if (st==null){ st = new Singleton3(); } } singleton = st; } } } return singleton; } }
静态内部类模式,里面会用到final 这个关键字,static final 的作用就是防止被改变。这样获取到的空间地址永远是不会改变的,这样就会保证只有一个实例存在,而且是线程安全的。具备有高并发和延时加载的优势。
public class Singleton4 { private static class SingletonDemo{ private static final Singleton4 singleton = new Singleton4(); } public Singleton4() { } public static Singleton4 getSingleton() { return SingletonDemo.singleton; } }
枚举单例,枚举本身就是单例,缺点就是没有延时加载。
public enum Singleton5 { SINGLETON; }
基于以上五种单例模式我们应该如何选择呢?如果是单例对象,占用资源较少,而且又不需要延时加载的话枚举式好于饿汉式。如果是单例对象,占用资源较大,而且需要延时加载的话静态内部类好于懒汉式。单例模式就到此结束了,平时我们使用的Application里面就涉及有单例模式。
相关文章推荐
- 如何在Tomcat中部署应用的多个版本
- PropertyChangeListener简单理解
- 什么是设计模式
- 设计模式之创建型模式 - 特别的变量问题
- 七、设计模式——装饰模式
- 设计模式总结
- 设计模式之创建型模式
- 浅谈设计模式的学习
- 设计模式---状态模式在web前端中的应用
- Ruby设计模式编程之适配器模式实战攻略
- 实例讲解Ruby使用设计模式中的装饰器模式的方法
- 设计模式中的模板方法模式在Ruby中的应用实例两则
- Ruby设计模式编程中对外观模式的应用实例分析
- 实例解析Ruby设计模式编程中Strategy策略模式的使用
- Ruby中使用设计模式中的简单工厂模式和工厂方法模式
- Ruby使用设计模式中的代理模式与装饰模式的代码实例
- 详解组合模式的结构及其在Ruby设计模式编程中的运用
- C# 设计模式系列教程-建造者模式
- C#编程中使用设计模式中的原型模式的实例讲解
- 使用设计模式中的工厂方法模式进行C#编程的示例讲解