设计模式(六):单例模式

一、概述

  单例模式确保一个类只有一个实例,并提供一个安全的访问点。

二、解决问题

  从概述中我们知道,单例模式就是保证系统的一个类只有一个实例。它的作用就是控制受限资源的访问,确保任何时刻都只有一个线程在访问一个受保护的资源。或者确保行为和状态的一致性,避免异常行为。在java web的程序中可能用到最多单例的地方就是jdbc的线程池。

三、结构类图

  

四、成员角色

  实例变量(uniqueInstance):持有唯一的单例实例,静态私有访问权限,只有本类才能访问该实例变量。

  全局访问方法(getInstance):提供全局的对单例实例的访问,任何时候都返回同一个单例实例(uniqueIntance),公共静态访问权限,任何对象都可以访问到。

五、应用实例

  单例模式有三种实现方案,我们来一起来看看如何实现。

  1.同步getInstance()方法

package singleton.pattern;

public class SynchronizedSingleton {
	//唯一的实例,只有本类才可以访问
	private static SynchronizedSingleton uniqueInstance;
	//只有本类才可以实例自己
	private SynchronizedSingleton(){

	}
	//提供对实例的全局访问点(同步方法,任何时候都只有一个线程可以访问该方法)
	public synchronized static SynchronizedSingleton getInstance(){
		if(uniqueInstance == null){
			uniqueInstance = new SynchronizedSingleton();
		}
		return uniqueInstance;
	}
}   

  2.“急切”创建实例

package singleton.pattern;

public class HurrySingleton {
	//唯一的一个类实例,用static把它变为静态的,在静态初始化器中创建单例
	private static HurrySingleton uniqueInstance = new HurrySingleton();

	private HurrySingleton(){
	}

	//已经有实例了直接返回
	public static HurrySingleton getInstance(){
		return uniqueInstance;
	}
}

  3.用“双重检查加锁”,减少同步

package singleton.pattern;

public class DoubleCheckSingleton {
	private volatile static DoubleCheckSingleton uniqueInstance;
	private DoubleCheckSingleton(){

	}

	public static DoubleCheckSingleton getInstance(){
		//线程只有第一次进入该方法时才会执行这个if代码
		if(uniqueInstance == null){
			//第一个线程获得类对象锁,其他线程就不能通过getInstance()方法获得实例了,
			synchronized(DoubleCheckSingleton.class){
				//这if判断是为了给第二个或者之后的线程获得类对象锁后使用,如果没有这个if判断,将会创建多个实例。
				//另外uniqueInstance变量必须要用volatile修饰,确保第一个线程实例化了对象后,其他线程能够立刻可见
				//volatile的详解请参考:http://www.cnblogs.com/dolphin0520/p/3920373.html(Java并发编程:volatile关键字解析)
				if(uniqueInstance == null){
					uniqueInstance = new DoubleCheckSingleton();
				}
			}
		}

		return uniqueInstance;
	}
}

  单例模式在jdbc中的应用,下面采用双重检查加锁实现数据库连接池的单例

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

import java.sql.SQLException;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Properties;

public class ConnectionMgr {

	    private volatile static BasicDataSource dataSource = null;

	    private ConnectionMgr() {
	    }

	    private static void init() {

	        if (dataSource != null) {
	            try {
	                dataSource.close();
	            } catch (Exception e) {
	                //
	            }
	            dataSource = null;
	        }

	        try {
	            Properties p = new Properties();
	            p.setProperty("driverClassName", MySys.getDriver());
	            p.setProperty("url", MySys.getDatabaseUrl());
	            p.setProperty("password", MySys.getDatabasePassword());
	            p.setProperty("username", MySys.getDatabaseUser());
	            System.out.print("OMS DB URL = "+MySys.getDatabaseUrl() + "\n");

	            p.setProperty("maxActive", "30"); //最大连接数量
	            p.setProperty("maxIdle", "10");   //最大空闲连接
	            p.setProperty("maxWait", "1000"); //超时等待时间以毫秒为单位 1000等于60秒

	            p.setProperty("removeAbandoned", "false"); //是否自动回收超时连接
	            p.setProperty("removeAbandonedTimeout", "120"); //超时时间(以秒数为单位)

	            p.setProperty("testOnBorrow", "true"); //指明是否在从池中取出连接前进行检验
	            p.setProperty("testOnReturn", "false"); //指明是否在归还到池中前进行检验
	            p.setProperty("testWhileIdle", "false");//指明连接是否被空闲连接回收器(如果有)进行检验

	            p.setProperty("logAbandoned", "true"); //连接被泄露时是否打印
	            p.setProperty("validationQuery", MySys.getTestQuery()); //

	            dataSource = (BasicDataSource) BasicDataSourceFactory.createDataSource(p);

	        } catch (Exception e) {
	            //
	        }
	    }

	    public static Connection getConnection() throws  SQLException {
	        Connection conn = null;
	        //双重检查加锁
	        if (dataSource == null) {
	        	synchronized(BasicDataSource.class){
	        		if (dataSource == null) {
	        			init();
	        		}
	        	}

	        }

	        if(dataSource != null){
	            conn = dataSource.getConnection();
	        }
	        return conn;
	    } 

六、优缺点

  1、同步getInstance()方法:最安全的单例,但是每次访问单例实例都要加锁,增加了性能的开销。如果系统对性能要求不高可以用。

  2、急切实例化:解决了“延迟实例化”带来的访问延迟问题,但会影响系统的启动负担,而如果该实例一开始创建了却一直没被用到会造成资源的浪费。系统启动和运行负担小可以用。

  3、双重检查加锁:减少了同步的使用,降低了jdk同步的开销;但是低版本的JDK不能使用,必须是1.5版本或者以上版本的JDK才能使用。系统对性能要求高时使用。

七、应用场景

  系统需要保证唯一的实例时使用,例如数据库连接池和线程池。

八、总结

  1.单例模式确保一个类中最多只有一个实例,并且提供访问这个实例的全局访问点。

  2.实现单例模式需要私有的构造器,一个私有静态变量和一个能够被公共访问的静态方法。

  3.如果使用多个类加载器,要小心单例失效而产生多个实例。

时间: 2024-10-07 21:02:56

设计模式(六):单例模式的相关文章

C#设计模式(1)——单例模式

一.引言 最近在设计模式的一些内容,主要的参考书籍是<Head First 设计模式>,同时在学习过程中也查看了很多博客园中关于设计模式的一些文章的,在这里记录下我的一些学习笔记,一是为了帮助我更深入地理解设计模式,二同时可以给一些初学设计模式的朋友一些参考.首先我介绍的是设计模式中比较简单的一个模式——单例模式(因为这里只牵涉到一个类) 二.单例模式的介绍 说到单例模式,大家第一反应应该就是——什么是单例模式?,从“单例”字面意思上理解为——一个类只有一个实例,所以单例模式也就是保证一个类只

C#设计模式之一单例模式(Singleton Pattern)【创建型】

原文:C#设计模式之一单例模式(Singleton Pattern)[创建型] 一.引言 看了李建忠老师的讲的设计模式已经有一段时间了(这段时间大概有一年多了),自己还没有写过自己的.有关设计模式的文章.这次想写一些关于设计模式的文章,用自己的理解和代码来写,算是复习一遍.写作的过程中也会多看看其他大牛的文章,争取让自己的理解正确,否则把大家带跑偏了,就是我的过错了.今天就开始我们第一个设计模式,该模式是:[单例模式],英文名称:Singleton Pattern,这个模式很简单,一个类型只需要

一天一个设计模式(二) -单例模式(Singleton)

前言 单例模式 (Singleton) 是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点. 正文 (一). 优缺点 Java中单例模式 (Singleton) 是一种广泛使用的设计模式.单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在.一些管理器和控制器常被设计成单例模式. 1. 优点 提供了对唯一实例的受控访问. 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象

Java设计模式:单例模式

概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,但只能

[转]JAVA设计模式之单例模式

原文地址:http://blog.csdn.net/jason0539/article/details/23297037 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话

设计模式 之 单例模式

单例模式思路: 私有化构造方法: 防止实例化 私有化克隆方法: 防止克隆 私有化静态属性: 保存对象 公有化静态方法: 获取对象 代码: <?php //设计模式:单例模式 class Singleton { //私有化静态属性:用于保存对象 private static $obj; //私有化构造方法 private function __construct(){} //公有化静态方法:用于实例化对象 public static function getObj() { //判断对象是否存在 i

设计模式实例学习-单例模式(Android中的使用场景)

1.设计模式实例-单例模式 单例模式,故名思议,是指在一个类中通过设置静态使得其仅创造一个唯一的实例.这样设置的目的是满足开发者的希望--这个类只需要被实例化创建一次,同时因为其为静态的缘故,加载的速度也应该快于正常实例化一个类的速度(理论上). 在Android开发中,当我们需要创建一个Fragment的时候常常会用到这样的模式,没有代码的学习是虚无的,接下来亮代码学习: public class SelectFrame extends Fragment { private final sta

(九)JAVA设计模式之单例模式

JAVA设计模式之单例模式 一.单例模式的介绍 Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点.     全局对象和Singleton模式有本质的区别,因为大量使用全局对象会使得程序质量降低,而且有些编程语言根本不支持全局变量.最重要的是传统的全局对象并不能阻止一个类被实例化多次. 二.单例模式的特点 单例类只能有一个实例 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例.

.NET设计模式之(单例模式)

1.单例模式,一个类只能new一个对象 2.举例,资源管理器,文件管理器,地球等: 3.创建单例: (1)创建一个Earth类 class Earth { public Earth() { } } (2)将构造函数 私有化 class Earth { private Earth() { } } (3)声明一个静态私有的字段,初始化一个实例 class Earth { private static Earth instance=new Earth(); private Earth() { } }

Java 设计模式(3)单例模式

前言 概念: java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,