设计模式之单例模式

单例模式:一个类只能有一个实例对象,对外提供一个访问实例的全局访问点
单例模式的优点:
由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理
单例模式的应用场景:
1、Spring容器中创建bean实例对象就是一种单例模式
2、servlet中每个servlet的实例
3、spring mvc和struts1框架中,控制器对象是单例模式
4、应用程序的日志应用,一般都是用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加
5、操作系统的文件系统,也是单例模式实现的具体例子,一个操作系统只能有一个文件系统
6、项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,每次new一个对象去读取。
7、数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源

单例模式之饿汉式

构成单例的条件:
1、保证不能让其他人使用构造器创建对象
2、提供一个静态方法,用于返回该对象
饿汉式单例模式:在类被加载的时候就创建好了实例

package com.zhouym.singletonpattern;

public class HungryMan {
	//类一加载就创建实例对象
	private static HungryMan instance = new HungryMan();
	
	//创建私有构造器,防止外界实例化
	private HungryMan(){}
	
	//对外提供共有的方法,返回实例对象
	public static HungryMan getInstance(){
		return instance;
	}
}

观察下上述代码的写法,会不会被什么破坏掉,仍然可以创建多个对象,答案是可以的,我们可以通过反射和序列化(后续整理)
通过反射获取对象

package com.zhouym.singletonpattern;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class singletonpatternTest {
	public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Class<?> classType = HungryMan.class;
		Constructor<?> c = classType.getDeclaredConstructor();
		c.setAccessible(true);
		HungryMan c1 = (HungryMan)c.newInstance();
		HungryMan c2 = HungryMan.getInstance();
		System.out.println(c1==c2);
	}
}

输出结果为:
在这里插入图片描述
说明c1与c2是两个对象,那么单例模式的只能创建一个实例对象的说法就不存在了,那么如何改进饿汉式的写法呢
改进后的单例模式之懒汉模式

package com.zhouym.singletonpattern;

public class HungryMan {
	//类一加载就创建实例对象
	private static HungryMan instance = new HungryMan();
	
	//创建私有构造器,防止外界实例化
	private HungryMan(){
		//增加一个如果这个实例对象存在了,就抛出一个异常,不能使其创建对象
		if (instance != null) {
			throw new RuntimeException();
		}
	}
	
	//对外提供共有的方法,返回实例对象
	public static HungryMan getInstance(){
		return instance;
	}
}

结果:
在这里插入图片描述

单例模式之懒汉式

懒汉式单例模式:在类的对象第一次使用时才创建该实例对象

package com.zhouym.singletonpattern;

public class Slacker {
	private static Slacker instance = null;	
	private Slacker(){}
	public static Slacker getInstance(){
		if (instance == null) {
			synchronized (Slacker.class) {
				if(instance == null){
					instance = new Slacker();
				}
			}
		}
		return instance;
	}
}

单例模式之双重检测锁式

public class SingletonInstance {
	// 声明此类型的变量,但没有实例化
	private static SingletonInstance instance = null;

	// 私有化所有的构造方法,防止直接通过new关键字实例化
	private SingletonInstance(){}
	// 对外提供一个获取实例的静态方法,
	public static  SingletonInstance getInstance(){
		if(instance == null){
			SingletonInstance s = null;
			synchronized(SingletonInstance.class){
				s = instance;
				if(s == null){
					synchronized(SingletonInstance.class){
						if(s == null){
							s = new SingletonInstance();
						}
					}
				}
				instance = s;
			}
		}
		return instance;
	}
}

这个模式将同步内容下方到if内部,提高了执行的效率不必每次获取对象时都进行同步,只有第一次才同步创建了以后就没必要了。
问题:由于编译器优化原因和JVM底层内部模型原因,偶尔会出问题。不建议使用。

静态内部类式

package com.zhouym.staticclass;


public class SingletonInstance {
	
	//构造方法私有
	private SingletonInstance() {}	
	//静态内部类
	private static class SingletonClassInstance{
		//声明外部类型的静态常量
		public static final SingletonInstance si = new SingletonInstance();
	} 	
	//对外提供唯一获取实例的方法
	public static SingletonInstance getInstance() {
		return SingletonClassInstance.si;
	}
}

1、外部类没有static属性,则不会像饿汉式那样立即加载对象。
2、只有真正调用getInstance(),才会加载静态内部类。加载类时是线程 安全的instance是static final类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全性.
3、兼备了并发高效调用和延迟加载的优势!– 兼备了并发高效调用和延迟加载的优势!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值