设计模式之单例模式

简介

单例模式是一种常用的设计模式,在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的一个类只有一个实例。即一个类只有一个对象的实例。比如:银行ATM系统对于bank这个类的话,就需要使用单例模式,来保证银行只有一个。

单例模式的优点

由于单例模式只生成一个实例,减少了系统性能的开销,当一个对象的产生需要较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动的时候直接产生一个单例对象,然后永久驻留内存的方式来解决。
单例模式可以在系统设置全局的访问点,优化共享资源访问。例如可以设计一个单例类,负责所有数据表的映射

两大步骤

1.将类的构造方法私有化,保证只能调用该类提供的静态方法来获得该类的唯一实例。
2.在该类中提供一个静态方法,调用该方法时判断该类的实例是否存在,存在就将实例返回,否则就创建该类的实例

单例模式之

饿汉式

public class SingletonDemo1 {
	//类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然线程安全
	private static SingletonDemo1 instance=new SingletonDemo1();
	private SingletonDemo1(){//私有化构造器
		
	}
	//方法没有同步,调用效率高
	static SingletonDemo1 getInstance(){
		return instance;
	}
}

测试代码一

public class Client {
	public static void main(String[] args) {
		SingletonDemo1 s1 = SingletonDemo1.getInstance();
		SingletonDemo1 s2 = SingletonDemo1.getInstance();
		System.out.println(s1);
		System.out.println(s2);
		System.out.println(s1==s2);
	}
}

运行结果一
在这里插入图片描述
通过比较可以两个是同一个对象。饿汉,饿汉!关键就是一个饿字。举个例子,做饭。大早上的就把今天一天要吃的早餐,中餐晚餐都提前做好。在这里的话,虽然暂时不需要使用这个对象,但是提前就创建好了,这就是饿汉式。

懒汉式

public class SingletonDemo2 {
	//类初始化时,不初始化这个对象(延时加载,真正用到的时候再创建)
	private static SingletonDemo2 instance;
	private SingletonDemo2(){
		//私有化构造器
	}
	//方法同步,调用效率低
	public static  synchronized SingletonDemo2 getInstance(){
		if(instance==null){
			instance=new SingletonDemo2();
		}
		return instance;
	}
}

测试代码二

public class Client {
	public static void main(String[] args) {
		SingletonDemo2 s1 = SingletonDemo2.getInstance();
		SingletonDemo2 s2 = SingletonDemo2.getInstance();
		System.out.println(s1);
		System.out.println(s2);
		System.out.println(s1==s2);
	}
}

测试结果二
在这里插入图片描述
同样的通过比较,两个还是同一对象。懒汉,懒汉,关键一个懒字。举个例子,同样也是做饭。还没到中午,但是懒的提前做中餐,等到了中午再做吧。这里的话,懒的创建对象,等用到这个对象的时候再来创建这个对象,这就是懒汉式。
懒汉式与饿汉式相反,可以对比着理解。

静态内部类

public class SingletonDemo3 {
	private static class SingletonClassInstance {
		private static final SingletonDemo3 instance = new SingletonDemo3();
	}

	public static SingletonDemo3 getInstance() {
		return SingletonClassInstance.instance;
	}

	private SingletonDemo3() {

	}
}

测试代码三

public class Client {
	public static void main(String[] args) {
		SingletonDemo3 s1 = SingletonDemo3.getInstance();
		SingletonDemo3 s2 = SingletonDemo3.getInstance();
		System.out.println(s1);
		System.out.println(s2);
		System.out.println(s1==s2);
	}
}

测试结果三
在这里插入图片描述
静态内部类实现单例模式,这种方式,线程安全,调用效率高,并且也实现了延时加载。
注意:
1.外部并没有static属性,则不会像饿汉式那样立即加载对象
2.只有真正调用getInstance()才会加载静态内部类。加载时是线程安全的。
3.instance是static final 类型,保证了内存中只有这样一个实例存在,而且只能赋值一次,从而保证线程安全
4.兼备了高并发和延时加载的优势

枚举

public enum SingletonDemo4 {
	//这个枚举元素,本身就是单例对象
	INSTANCE;
	//可以添加自己需要的操作
	public void singletonOperation(){
		//功能以及处理
	}
}

测试代码四

public class Client {
	public static void main(String[] args) {
		System.out.println(SingletonDemo4.INSTANCE == SingletonDemo4.INSTANCE);
	}
}

测试结果四
在这里插入图片描述

几种单例模式对比

创建10个线程,每个线程执行100000000次,每次都去获得instance对象。

public class Client2 {
	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		int threadNum=10;
		final CountDownLatch countDownLatch=new CountDownLatch(threadNum);
		
		for(int i=0;i<threadNum;i++){
			new Thread(new Runnable() {
				
				public void run() {
					for(int i=0;i<100000000;i++){
						Object object=SingletonDemo1.getInstance();
						//Object o = SingletonDemo4.INSTANCE;//枚举
					}
					countDownLatch.countDown();
				}
			}).start();
		}
		countDownLatch.await();//main线程阻塞,直到计数器变为0,才会继续往下执行
		long end = System.currentTimeMillis();
		System.out.println("总共消耗时间:"+(end-start));
	}
}

测试结果
饿汉式在这里插入图片描述
懒汉式在这里插入图片描述
静态内部类在这里插入图片描述
枚举在这里插入图片描述

饿汉式:线程安全,调用效率高,不能延时加载
懒汉式:线程安全,调用效率不高,但是可以延时加载
静态内部类式:线程安全,调用效率高,也可以延时加载
枚举式:线程安全,调用效率高,并且可以天然防止反射和反序列化漏洞

如何选用

当 单例对象 占用资源少,不需要延时加载: 枚举式 好于 饿汉式
当 单例对象 占用资源大,需要延时加载: 静态内部类式 好于 懒汉式

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值