要求
写一个类, 它只能有一个实例, 既多次声明这个类拿到的都是同一个东西. 要求这个功能的代码只在这个类里.
•
1、单例类只能有一个实例。
•
2、单例类必须自己创建自己的唯一实例。
•
3、单例类必须给所有其他对象提供这一实例
实现
1.
DCL (双锁检测)
spring 就是用的这种, 这种是多语言通用的, 线程安全 .
public class Singleton{
private static volatile Singleton instance;
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
private Singleton(){}
}
2.
initialization on demand holder idiom
只能是static, 优点是简洁
public class instaceFactory{
private class holder{
public static Instance instance = new Instance();
}
public static Instance getInstance(){
return holer.instance;
}
}
3.
懒汉模式
•
不会从开头就浪费内存,但是因为是同步方法所以性能低.
public class SingleClass{
private static SingleClass instance;
private SingleClass(){}
public synchronized static SingleClass newInstance(){
if (instace == null)
instance = = new SingleClass();
return instance;
}
}
4.
饿汉模式
public class SingleClass{
private static SingleClass instance = new SingleClass();
private SingleClass(){}
public static SingleClass newInstance(){
return instance;
}
}
5.
单例注册表 (Spring 使用)
Import java.util.HashMap;
Public class RegSingleton{
Static private HashMap registry=new HashMap();
//静态块,在类被加载时自动执行
Static{
RegSingleton rs=new RegSingleton();
Registry.put(rs.getClass().getName(),rs);
}
//受保护的默认构造函数,如果为继承关系,则可以调用,克服了单例类不能为继承的缺点
Protected RegSingleton(){}
//静态工厂方法,返回此类的唯一实例
public static RegSingleton getInstance(String name){
if(name==null)
name=” RegSingleton”;
if(registry.get(name)==null){
try{
registry.put(name,Class.forName(name).newInstance());
}Catch(Exception ex){ex.printStackTrace();}
}
Return (RegSingleton)registry.get(name);
}
}
public abstract class AbstractBeanFactory implements ConfigurableBeanFactory{
// 充当了Bean实例的缓存,实现方式和单例注册表相同
private final Map singletonCache=new HashMap();
public Object getBean(String name)throws BeansException{
return getBean(name,null,null);
}
...
public Object getBean(String name,Class requiredType,Object[] args)throws BeansException{
//对传入的Bean name稍做处理,防止传入的Bean name名有非法字符(或则做转码)
String beanName=transformedBeanName(name);
Object bean=null;
//手工检测单例注册表
Object sharedInstance=null;
//使用了代码锁定同步块,原理和同步方法相似,但是这种写法效率更高
synchronized(this.singletonCache){
sharedInstance=this.singletonCache.get(beanName);
}
if(sharedInstance!=null){
...
//返回合适的缓存Bean实例
bean=getObjectForSharedInstance(name,sharedInstance);
}else{
...
//取得Bean的定义
RootBeanDefinition mergedBeanDefinition=getMergedBeanDefinition(beanName,false);
...
//根据Bean定义判断,此判断依据通常来自于组件配置文件的单例属性开关
//<bean id="date" class="java.util.Date" scope="singleton"/>
//如果是单例,做如下处理
if(mergedBeanDefinition.isSingleton()){
synchronized(this.singletonCache){
//再次检测单例注册表
sharedInstance=this.singletonCache.get(beanName);
if(sharedInstance==null){
...
try {
//真正创建Bean实例 ,这里在多例模式里直接就能用了,为什么还要再来一步.
sharedInstance=createBean(beanName,mergedBeanDefinition,args);
//向单例注册表注册Bean实例
addSingleton(beanName,sharedInstance);
}catch (Exception ex) {
...
}finally{
...
}
}
}
bean=getObjectForSharedInstance(name,sharedInstance);
}
//如果是非单例,即prototpye,每次都要新创建一个Bean实例
//<bean id="date" class="java.util.Date" scope="prototype"/>
else{
bean=createBean(beanName,mergedBeanDefinition,args);
}
}
...
return bean;
}
}
例子
public class MySqlSessionFactory {
private MySqlSessionFactory() {//构造函数私有化
}
public static SqlSession getSqlSession() throws FileNotFoundException {
return new sql().sqlSession;
}
//利用内部类只有在使用的时候才加载的原理来延迟加载。
public static class sql {
public SqlSession sqlSession = (new SqlSessionFactoryBuilder().build(new FileReader("./src/sqlMapConfig.xml"))).openSession();
public sql() throws FileNotFoundException {
}
}
}
评论区