[zt]Singleton和Double-Checked Locking设计模式—UML图及代码实现

简介:

Singleton和Double-Checked Locking设计模式,分别指的是单例模式和双重检查锁模式,它们都可以用于确保某个类只有一个对象实例化。

两个模式的区别在于:Singleton模式用在单线程应用程序中,而Double-Checked Locking模式用于多线程模式。

一、Singleton模式

UML图:

代码:

 

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. package bupt.xujinliang.singletonpattern;  
  2. /** 
  3.  *  
  4.  * @author jin 
  5.  * 
  6.  */  
  7. public class SingletonExample {  
  8.     public static void main(String[] args) {  
  9.         Printer printer1 = Printer.getInstance();  
  10.         Printer printer2 = Printer.getInstance();  
  11.         if(printer1 == printer2) {  
  12.             System.out.println("printer2 point to the same address with printer1");  
  13.         } else {  
  14.             System.out.println("printer2 point to different address with printer1");  
  15.         }  
  16.     }  
  17. }  
  18. class Printer {  
  19.     private static Printer instance;  
  20.     public Printer() {  
  21.         System.out.println("Printer Constructor");  
  22.     }     
  23.     public static Printer getInstance() {  
  24.         if(null == instance)   
  25.             instance = new Printer();  
  26.         return instance;  
  27.     }  
  28. }  


运行结果:

 

2.Double-Checked Locking模式

Double Check Locking模式是singleton的多线程版本,必须使用锁来锁定临界区,当多个线程存在访问临界区的意图时,保证了临界区只被访问一次。
首先介绍其在C/C++环境下的实现过程:
代码1:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. Printer* get_instance(void)  
  2. {  
  3.     lock();  
  4.     if( instance == 0) {  
  5.        instance = new Printer;  
  6.     }  
  7.     unlock();  
  8.     return instance;  
  9. }  
上述代码存在的问题是:无论是否已经初始化都要加锁,增加了负荷,已经没有所谓的并发性能了。
代码2:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. Printer* get_instance(void)  
  2. {   
  3.     if( instance == 0){  
  4.         lock();  
  5.         instance = new Printer;  
  6.         unlock();  
  7.     }  
  8.     return instance;  
  9. }  
上述代码存在的问题是:不能保证临界区只初始化一次,没能实现singleton的基本功能。
代码3:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. Printer* get_instance(void)  
  2. {   
  3.     if( instance == 0){  
  4.         lock();  
  5.         if( instance == 0 )  
  6.             instance = new Printer;  
  7.         unlock();  
  8.     }  
  9.     return instance;  
  10. }  
这是比较完善的Double-Checked Locking模式实现的代码。
为什么叫做Double-Checked Locking呢?请看上述代码3,可以看到在加锁前后都对instance变量进行了检查,故谓之Double-Checked Locking。
那么在Java中的实现与在C/C++中不同吗?是的。
下面的的Java代码是不能够实现Double-Checked Locking模式的:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. class Printer {  
  2.     private static Printer resource ;  
  3.     public static Printer getInstance(){      
  4.         if(resource == null ){  
  5.             synchronized (DoubleCheckedLockingExample.class) {  
  6.                 if(resource  == null ){  
  7.                     resource  = new Printer() ;  
  8.                 }  
  9.             }             
  10.         }         
  11.         return resource ;  
  12.     }     
  13.     private Printer(){}  
  14. }  
上面程序真正的问题是没有同步的情况下读取共享变量resource,并发的情况下对象的状态值有可能是过期无效的。要解决这个问题也很简单,把resource声明为volatile类型。volatile有什么作用?引用《java并发编程实战》的解析:
[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. 当一个域声明为volatile类型后,编译器与运行时会监视这个变量:它是共享的,而且对它的操作不会与其他的内存操作一起被重排序。volatile变量不会缓存在寄存器或缓存在对其他处理器隐藏的地方。所以,读一个volatile类型的变量时,总会返回由某一线程所写入的最新值。  
读取volatile变量比读取非volatile变量的性能几乎没有差别,不过需要注意的是volatile只能保证内存可见性,并不能保证原子性。
现给出Java在多线程下实现单个实例化对象的方法:
[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
  1. class Printer {  
  2.     private static class Instance {  
  3.         static final Printer instance = new Printer();  
  4.     }  
  5.     private static Printer resource ;  
  6.     public static Printer getInstance(){          
  7.         return Instance.instance;  
  8.     }     
  9.     private Printer(){}  
  10. }  
上述方法之所以有效,是因为内部类(Instance)将只被装载一次,所以只会创建一个对象。

本文转自博客园Grandyang的博客,原文链接:[zt]Singleton和Double-Checked Locking设计模式—UML图及代码实现

,如需转载请自行联系原博主。

相关文章
|
22天前
|
设计模式 存储 Java
23种设计模式,备忘录模式的概念优缺点以及JAVA代码举例
【4月更文挑战第9天】备忘录模式是一种行为设计模式,它能在不破坏对象封装的前提下,捕获并保存对象的当前状态,以便后面可以恢复到这个状态。
36 0
|
13天前
|
设计模式 安全 Java
设计模式-单例 Singleton
设计模式-单例 Singleton
18 1
|
22天前
|
设计模式 前端开发 API
写出易维护的代码|React开发的设计模式及原则
本文对React社区里出现过的一些设计模式进行了介绍,并讲解了他们遵循的设计原则。
|
22天前
|
设计模式 存储 Java
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
|
22天前
|
设计模式 存储 Java
Java设计模式:解释一下单例模式(Singleton Pattern)。
`Singleton Pattern`是Java中的创建型设计模式,确保类只有一个实例并提供全局访问点。它通过私有化构造函数,用静态方法返回唯一的实例。类内静态变量存储此实例,对外仅通过静态方法访问。
19 1
|
22天前
|
设计模式 算法 Java
23种设计模式,访问者模式的概念优缺点以及JAVA代码举例
【4月更文挑战第10天】访问者模式是一种将算法与对象结构分离的设计模式。这种模式主要用于执行一个操作(或一组操作)在一个对象结构的各元素上,它可以在不修改各元素的类的前提下定义新的操作。
27 2
|
22天前
|
设计模式 算法 Java
23种设计模式,模板方法模式的概念优缺点以及JAVA代码举例
【4月更文挑战第10天】模板方法模式是一种行为设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些特定步骤。
22 0
|
22天前
|
设计模式 算法 搜索推荐
23种设计模式,策略模式的概念优缺点以及JAVA代码举例
【4月更文挑战第10天】设计模式是软件工程中的一种最佳实践指导,用于解决常见的设计问题。它们被分类为创建型、结构型和行为型模式。其中,策略模式是一种行为型设计模式,旨在定义一系列算法,封装每一个算法,并使它们可互换。策略模式允许算法独立于使用它们的客户端变化
29 2
|
22天前
|
设计模式 Java
23种设计模式,状态模式的概念优缺点以及JAVA代码举例
【4月更文挑战第9天】状态模式是一种行为设计模式,允许一个对象在其内部状态改变时改变它的行为,这个对象看起来似乎修改了它的类。
30 4
|
22天前
|
设计模式 Java
23种设计模式,观察者模式的概念优缺点以及JAVA代码举例
【4月更文挑战第9天】观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象改变状态时,所有依赖于它的对象都会得到通知并自动更新。
31 2