解决的问题
希望某个对象在全局(或在某个范围内)只有一个。为什么要只有一个,为了全局共享。
单例的基本思维
对应用中的通用对象设置调用方法,而不是直接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