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

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

一、Singleton模式

UML图:

代码:

  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:
  1. Printer* get_instance(void)
  2. {
  3. lock();
  4. if( instance == 0) {
  5. instance = new Printer;
  6. }
  7. unlock();
  8. return instance;
  9. }

上述代码存在的问题是:无论是否已经初始化都要加锁,增加了负荷,已经没有所谓的并发性能了。

代码2:
  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:
  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模式的:
  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并发编程实战》的解析:

  1. 当一个域声明为volatile类型后,编译器与运行时会监视这个变量:它是共享的,而且对它的操作不会与其他的内存操作一起被重排序。volatile变量不会缓存在寄存器或缓存在对其他处理器隐藏的地方。所以,读一个volatile类型的变量时,总会返回由某一线程所写入的最新值。

读取volatile变量比读取非volatile变量的性能几乎没有差别,不过需要注意的是volatile只能保证内存可见性,并不能保证原子性。

现给出Java在多线程下实现单个实例化对象的方法:
  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)将只被装载一次,所以只会创建一个对象。

[zt]Singleton和Double-Checked Locking设计模式—UML图及代码实现的更多相关文章

  1. Java中的双重检查锁(double checked locking)

    最初的代码 在最近的项目中,写出了这样的一段代码 private static SomeClass instance; public SomeClass getInstance() { if (nul ...

  2. Double Checked Locking 模式

    转自:http://blog.csdn.net/wwsoon/article/details/1485886 之前在使用Double Check Locking 模式时,发现自己还是不太理解.于是写个 ...

  3. 设计模式-UML图简单介绍

    直接上法宝: 1.类(Class)     类图分三层:     第一层显示类的名称,如果是抽象类,则就用斜体显示.     第二层是类的特性,通常就是字段和属性.     第三层是类的操作,通常是方 ...

  4. 设计模式UML图

    1.简单工厂模式 2.工厂模式 工厂模式与简单工厂模式的不同在于,每个操作类都有自己的工厂,而且把逻辑判断交给了客户端,而简单工厂的逻辑判断在工厂类里边,当增加新的操作类时,简单工厂需要修改工厂类,而 ...

  5. 【转】23种设计模式UML图

    原文:http://blog.csdn.net/bwwlpnn/article/details/7421628

  6. 三类设计模式UML图

    http://design-patterns.readthedocs.org/zh_CN/latest/index.html

  7. 23种设计模式UML图

  8. 设计模式 UML & java code

    A: 创造性模式 1. 工厂方法模式(FactoryMethod) 1.1 类图 1.2 代码1 public interface Pet { public String petSound(); } ...

  9. 23种经典设计模式UML类图汇总

    在这里23种经典设计模式UML类图汇总       创建型模式 1.FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基 ...

随机推荐

  1. 19条ANDROID平台设计规范(转)

    1.尺寸以及分辨率: Android的界面尺寸比较流行的有:480*800.720*1280.1080*1920,我们在做设计图的 时候建议是以 480*800的尺寸为标准; 2.界面基本组成元素: ...

  2. 通讯录(ios自带有界面)

    1.添加AddressBookUI.framework框架 2控制器中实现 #import "ViewController.h" #import <AddressBookUI ...

  3. MFC 丢失MSVCR120D.dll 丢失mfc120ud.dll

  4. $(function(){})与window.onload的区别

    不太一样window.onload是在页面所有的元素都加载完成后才触发$(function(){})是在页面的dom结构加载完毕后就触发 dom里的内容不一定都已经加载完成比如说一个页面有好多图片 而 ...

  5. java Clone使用方法详解

    java"指针"       Java语言的一个优点就是取消了指针的概念,但也导致了许多程序员在编程中常常忽略了对象与引用的区别,本文会试图澄清这一概念.并且由于Java不能 通过 ...

  6. session应用----登录验证小案例

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  7. kylin cube测试时,报错:org.apache.hadoop.security.AccessControlException: Permission denied: user=root, access=WRITE, inode="/user":hdfs:supergroup:drwxr-xr-x

    异常: org.apache.hadoop.security.AccessControlException: Permission denied: user=root, access=WRITE, i ...

  8. background为圆角的表框,dp转Px,Px转dp

    圆角边框<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="ht ...

  9. 使用Eclipse将Web项目打Jar包方法

    1.对下载.安装和运行Eclipse,就不再说了: 2.找到待打包项目: 3.右键,Export-->Export: 4.选择,Jar: 5.按如图操作: 6.完成后:

  10. hdu2639 01背包第K优解

    #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #i ...