单例模式的思想简介

解决的问题

希望某个对象在全局(或在某个范围内)只有一个。为什么要只有一个,为了全局共享。

单例的基本思维

对应用中的通用对象设置调用方法,而不是直接new。

比如数据库连接。如果用hibernate,就会在应用初始化时,就创建数据库连接。在访问时通过方法,而不是通过new产生。

对比其他的几种做法:

1在需要时new连接对象,用完后关闭。这样频繁的开和关,效率低。同时代码融入很多无关的成分。

2在初始化时new,放到全局区,比如java web的application context中。这种访问太直接了。

单例的经典实现

public class Singleton {

//定义一个私有的静态全局变量来保存该类的唯一实例

private static Singleton singleton;

//构造函数必须是私有的,这样在外部便无法使用 new 来创建该类的实例

private Singleton() {

}

//定义一个全局访问点 ,设置为静态方法,则在类的外部便无需实例化就可以调用该方法

public static Singleton GetInstance() {

//这里可以保证只实例化一次,即在第一次调用时实例化 ,以后调用便不会再实例化

if (singleton == null) {

singleton = new Singleton();

}

return singleton;

}

}

单例的本质

1单例不一定是一个的

比如qq软件的登录状态对象,我们希望每个用户在某一时刻只有一个登录状态对象,不可以在两台机子同时上q。那么在服务端就会为每个用户的登录状态建立一个单例。比如

class  User {

static  private  $_instance = array();//静态成员保存唯一实例

private $_uid ;

//私有构造函数,保证不能被外部访问

private function __construct($uid ) {

$this->_uid = $uid;

}

public static function getInstance($uid = 0) {

if (!self::$_instance || !isset(self::$_instance[$uid]) ) {

self::$_instance[$uid] = new self($uid);

}

return self::$_instance[$uid];

}

}

2代码形式也不是必要的

spring中,我们可以把某些对象(比如userDaoImpl和userService等)设成单例,因为这些对象在应用只需要一个,但你在用spring时没有用getInstance这个函数吧。更重要的是不直接new,而是调用方法产生。

3单例的本质在于共享

共享有中情况:

由于使用共享的资源(如static,文件等),不得不由共享对象来操作。

某对象比较复杂,不应该每个使用者都创建一个,所以共享。

单例的重要概念

1单例的生存周期。单例什么时候会销毁。有的是request级的,有的是session级的,有的是application级的。这主要看单例依赖于什么。比如登录信息放在session中,就会是session基本的。又比如最常见的static形式的单例,由于static属于类成员,只有在应用停止时才会销毁,所以是application基本的。

2单例与多线程。既然单例共享资源,就一定要考虑多线程问题。对操作共享资源的函数,就要加同步了。百闻不如一见,还是贴一段代码,代码的背景是这样的,数据库中存了树形结构的数据,这个类RoleTree把树结构读出来,缓存到static中。作为一个单例给需要使用这颗树的地方调用。

  1 package com.xcat.user;
  2
  3 import java.sql.Connection;
  4 import java.sql.PreparedStatement;
  5 import java.sql.SQLException;
  6 import java.util.ArrayList;
  7 import java.util.HashMap;
  8 import java.util.HashSet;
  9 import java.util.LinkedList;
 10 import java.util.List;
 11 import java.util.Map;
 12 import java.util.Queue;
 13 import java.util.Set;
 14
 15 import com.xcat.common.DB;
 16
 17 public class RoleTree {
 18     private Map<Integer,Role> treeUp;
 19     private Map<Integer,Set<Integer>> treeDown;
 20     private static RoleTree instance = null;
 21     private RoleDao roleDao;
 22
 23     private RoleTree() {
 24         roleDao = new RoleDao();
 25         reinit(roleDao.list());
 26     }
 27
 28     public static synchronized RoleTree getInstance() {
 29         if (instance == null) {
 30             instance = new RoleTree();
 31         }
 32         return instance;
 33     }
 34
 35     public void reinit(List<Role> ls){
 36
 37         treeUp = new HashMap<Integer,Role>();
 38         treeDown = new HashMap<Integer,Set<Integer>>();
 39         for(Role r : ls){
 40             treeUp.put(r.getId(), r);
 41             treeDown.put(r.getId(), new HashSet<Integer>());
 42         }
 43         treeDown.put(0,new HashSet<Integer>());
 44         for(Role r : ls){
 45             treeDown.get(r.getParentId()).add(r.getId());
 46         }
 47     }
 48
 49     public synchronized void add(Role r){
 50         roleDao.add(r);
 51         r= roleDao.loadByName(r.getName());
 52         treeUp.put(r.getId(), r);
 53         treeDown.put(r.getId(), new HashSet<Integer>());
 54         treeDown.get(r.getParentId()).add(r.getId());
 55
 56     }
 57
 58     public void addAsRoot(Role r){
 59         r.setParentId(0);
 60         add(r);
 61     }
 62
 63     public void addByParent(Role r,int parentId){
 64         r.setParentId(parentId);
 65         add(r);
 66     }
 67
 68     public List<Role> getChildren(int id){
 69         List<Role> ls= new ArrayList<Role>();
 70         Queue<Integer> queue = new LinkedList<Integer>();
 71         queue.offer(id);
 72         while (queue.peek()!=null){
 73             int cur=queue.poll();
 74             ls.add(treeUp.get(cur));
 75             Set<Integer> set=treeDown.get(cur);
 76             if(set!=null)
 77                 for(int i : set) queue.offer(i);
 78         }
 79
 80         for(Role r : ls)
 81             if(r.getId()==0) {
 82                 ls.remove(r);
 83                 break;
 84             }
 85
 86         return ls;
 87     }
 88
 89     public List<Role> list(){
 90         List<Role> ls= new ArrayList<Role>();
 91         for(Role r : treeUp.values()){
 92             ls.add(r);
 93         }
 94
 95         for(Role r : ls)
 96             if(r.getId()==0) {
 97                 ls.remove(r);
 98                 break;
 99             }
100
101         return ls;
102     }
103
104     public Role loadById(int id) {
105         Role r;
106         if(treeUp.containsKey(id)) r=treeUp.get(id);
107         else r=null;
108         return r;
109     }
110
111     public List<Object[]> getIndentName(){
112         List<Object[]> ls= new ArrayList<Object[]>();
113         for(int i : treeDown.get(0)) _getInent(ls,i,0);
114         return ls;
115     }
116
117     private void _getInent(List<Object[]> ls, int cur ,int level){
118
119         Object[] objs =new Object[2];
120         objs[0]=treeUp.get(cur).getId();
121         String name="";
122         for(int i=0;i<level;i++) name+="-";
123         objs[1]=name+treeUp.get(cur).getName();
124         ls.add(objs);
125
126         for(int i : treeDown.get(cur))
127             _getInent(ls,i,level+1);
128     }
129
130     private void showTreeDown(){
131         for(int key : treeDown.keySet()) {
132             for(int i : treeDown.get(key)) System.out.print(i+",");
133             System.out.println("");
134         }
135     }
136
137     public synchronized  void update(Role r) {
138         roleDao.update(r);
139
140         int oldId=treeUp.get(r.getId()).getParentId();
141         treeDown.get(oldId).remove(r.getId());
142         treeUp.remove(r.getId());
143
144         treeUp.put(r.getId(), r);
145         treeDown.get(r.getParentId()).add(r.getId());
146     }
147
148     public synchronized void updateParent(int id , int parentId) {
149         roleDao.updateParent(id, parentId);
150
151         int oldId=treeUp.get(id).getParentId();
152         treeDown.get(oldId).remove(id);
153
154         treeUp.get(id).setParentId(parentId);
155         treeDown.get(parentId).add(id);
156     }
157
158     public void delete(Role r) {
159         deleteById(r.getId());
160     }
161
162     public synchronized boolean deleteById(int id) {
163         if(treeDown.get(id).size()!=0) return false;
164
165         roleDao.deleteById(id);
166
167         int oldId=treeUp.get(id).getParentId();
168         treeUp.remove(id);
169         treeDown.get(oldId).remove(id);
170         treeDown.remove(id);
171         return true;
172     }
173
174     public synchronized void deleteBranch(int id) {
175         List<Role> ls=getChildren(id);
176         System.out.println("size:"+ls.size());
177         List<Integer> lsi=new ArrayList<Integer>();
178         for(Role r : ls) lsi.add(r.getId());
179         roleDao.deletebyIds(lsi);
180
181         reinit(roleDao.list());
182     }
183 }

单例与多线程示例

实际例子

数据库连接

实现代码

http://www.cnblogs.com/BoyXiao/archive/2010/05/07/1729376.html?login=1

类关系(类图)

参考文章:http://blog.csdn.net/hguisu/article/details/7515416

时间: 2024-07-31 22:38:15

单例模式的思想简介的相关文章

白话经典算法二叉堆排序之思想简介

常用的排序算法有冒泡排序,插入排序和选择排序.他们的时间复杂度是o(n2),与数据量的平方成正比.他们的效率还是比较低的.现在来说说他们的效率为什么比较低下.以冒泡排序为例,它每一轮都是与相邻的元素进行交换,交换的距离为1,每次每个(没有冒泡出来的)元素都要与前一个比较再交换.每次相邻的比较只能比较出两个元素的大小,不能以整个数组进行参照来确定在整个数组里的大小,也就是说每次的比较不能确定其他元素的相对位置,因而每次比较的贡献不大,所以这样的比较是笨拙的,进而需要完全比较O(n2)次才能得出正确

hadoop学习笔记(二)——hadoop思想简介

这几天阅读<hadoop实战>,初步了解了一下hadoop的核心思想,简要的比较如下: 1.  hadoop是一个开源框架,可编写和运行分布式应用处理大数据,具有方便.简单.健壮性.可扩展性等优点 2.  MapReduce程序的执行分为两个阶段,为mapping和reducing.每个阶段均定义为数据处理函数,分别被称为mapper和reducer.在mapping阶段,MapReduce获取输入数据并将数据单元装入mapper:在reducing阶段,reducer处理来自mapper的所

转: MVC设计思想简介

模型-视图-控制器(MVC)是80年代Smalltalk-80出现的 一种软件设计模式,现在已经被广泛的使用. 1.模型(Model) 模型是应用程序的主体部分.模型表示业务数据,或者业务逻辑. 2.视图(View) 视图是应用程序中用户界面相关的部分,是用户看到并与之交互的界面. 3.控制器(controller) 控制器工作就是根据用户的输入,控制用户界面数据显示和更新model对象状态. MVC 式的出现不仅实现了功能模块和显示模块的分离,同时它还提高了应用系统的可维护性. 早期的程序中,

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

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

c# 单例模式[Singleton]之深夜闲聊

都有点记不起认识单例模式(也有叫单件模式的)是在什么时候了,有时候东西认多了不常用的话也经常抛之脑后甚至逐渐从大脑里被移除.不闲扯了,直接入正题吧. 什么是单例模式? 保证在整个应用程序的生命周期中,在任何时刻,被指定的类只有一个实例,并为客户程序提供一个获取该实例的全局访问点. 单例模式的作用? 被指定的类在整个应用程序只会被创建一次. 接着我们用代码来加深对单例模式的理解.在这之前我们都知道如果一个类在没有使用单例模式的情况下是可以被实例化多次对象的,比如下面代码: 这里我先创建一个类: 1

Java设计模式之单例模式(恶汉式和懒汉式)

/* * 单例模式: *         饿汉式:类一加载就创建对象 *         懒汉式:用的时候,才去创建对象 * 面试题:单例模式的思想是什么?写一个代码体现(我们最好写懒汉式的单例模式给面试官,这个才是他想要的答案) *         开发使用:恶汉式(是不会出问题的单例模式) *         面试时写懒汉式(可能会出现问题的单例模式) *             A:懒汉式(延迟加载) *             B:线程安全问题 *                 a:是

单例模式那件小事,看了你不会后悔

欢迎关注下文:单例模式不是一件小事,快回来看看. 单例模式是一种创建型模式,某个类采用单例模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点. 主要思想如下: 将构造方法私有化( 声明为 private ),这样外界不能随意 new 出新的实例对象: 声明一个私有的静态的实例对象,供外界使用: 提供一个公开的方法,让外界获得该类的实例对象. 具体实现代码如下: 代码① public class Singleton { /** * 构造方法私有化 */ private

单例模式那件小事,看了你不会后悔(转)

原文地址:http://www.cnblogs.com/joy99/p/6262465.html 单例模式是一种创建型模式,某个类采用单例模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点. 主要思想如下: 将构造方法私有化( 声明为 private ),这样外界不能随意 new 出新的实例对象: 声明一个私有的静态的实例对象,供外界使用: 提供一个公开的方法,让外界获得该类的实例对象. 具体实现代码如下: 代码① public class Singleton {

paper 35 :交叉验证(CrossValidation)方法思想

交叉验证(CrossValidation)方法思想简介 以下简称交叉验证(Cross Validation)为CV.CV是用来验证分类器的性能一种统计分析方法,基本思想是把在某种意义下将原始数据(dataset)进行分组,一部分做为训练集(train set),另一部分做为验证集(validation set),首先用训练集对分类器进行训练,在利用验证集来测试训练得到的模型(model),以此来做为评价分类器的性能指标.常见CV的方法如下: 1).Hold-Out Method 将原始数据随机分