java 单例设计模式(详细)

单例设计模式(Singleton)

一、什么是单例设计模式:
所谓类的单例设计模式,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例(servlet就是单例的)

二、如何实现单例设计模式(饿汉模式和懒汉模式)
(一)思路:
1、为了让整个软件系统中只有一个 特定类的对象,就不能让该类在别处可以创建类对象,为了达到这个效果,需要私有化构造器。
2、私有化构造器后,无法在类的外部创建类的对象实例,而我们单例模式又需要一个对象实例,所以需要在类内部创建一个对象实例。
3、在类的内部创建类的实例以后,为了在类的外部使用这个对象实例,类中需要一个静态的公共方法返回这个对象实例(为什么要静态方法?因为在类外部无法创建类的对象实例,所以只能调用静态方法)。
4、由于这个公共的方法是静态的,所以在创建这个对象实例的时候,也需要声明成静态的(静态方法内不能使用非静态的成员变量)
(二)代码实现
1、饿汉模式:(直接创建类的对象实例)

//饿汉式单例模式
public class SingletonText1 {
	public static void main(String[] args) {
		Bank bank1 = Bank.getInstance();
		Bank bank2 = Bank.getInstance();
		//bank1和bank2 都是同一个对象
		System.out.println("bank1="+bank1);
		System.out.println("bank2="+bank2);
	}
}

class Bank{
	//1、私有化类的构造器(避免在类的外部new 多个对象)
	private Bank() {}
	//2、内部创建类的对象
	private static Bank instance = new Bank();
	//3、提供公共的方法,返回类对象(为了在类外面调用这个方法,类外面又不能创建类的实例,所以方法只能为静态的)
	public static Bank getInstance() {
		return instance;//4、要在静态的方法中使用对象,那么对象的定义也应该是静态的
	}
}

可以看出运行结果,获取的两个Bank类型的变量指向的是同一个对象可以看出,运行结果显示,两个Bank为同一个对象。

2、懒汉模式(线程不安全):(需要对象实例时才创建对象)

class Order{
	//1、私有化类的构造器
	private Order() {}
	//2、声明类的对象,不初始化
	private static Order instance = null;
	//3、声明一个public的static的返回当前对象的方法
	public static Order getInstance() {
		if(instance == null) {//5、如果每次调用方法都 new 一个对象,那么就违背了单例模式只能创建一个对象的初衷,所以加一个null判断			
			instance = new Order();//4、由于要在静态的方法中使用instance,所以instance的声明应该是静态的
		}
		return instance;
	}
}

存在的问题:
线程不安全,当线程A进入if条件语句但是还没有创建对象实例就发生阻塞,另一个线程B进入if语句后创建对象实例。之后线程A再次激活获得cpu资源继续运行,既可以不经过if判断直接创建对象实例。这样线程A和线程B均创建了不同的对象,不再是单例的了。

解决线程安全问题的思路:
线程安全的问题存在的实质是,存在多个线程进入到if判断内。也就是if判断中同时存在多个线程(例如上面所说的线程A和B,它们同时在if代码块中,只是A处于堵塞状态)。为了解决这个问题,只需要当有线程进入if判断内,就不允许其他线程进入if判断内,通过同步锁就可以实现,将if语句锁起来。

3、懒汉模式(线程安全):

class Order{
	//1、私有化类的构造器
	private Order() {}
	//2、声明类的对象,不初始化
	private static Order instance = null;
	//3、声明一个public的static的返回当前对象的方法
	public static Order getInstance() {
	//6.为了解决线程安全问题,通过一个同步锁,锁住代码块,只要一个线程进入同步代码块中没有执行完整个代码块,那么就没有线程可以进入代码块,也就不能通过if语句。也就是说,不会出现两个线程均在if判断内。
		synchronized(Order.class){
			if(instance == null) {//5、如果每次调用方法都 new 一个对象,那么就违背了单例模式只能创建一个对象的初衷,所以加一个null判断			
			instance = new Order();//4、由于要在静态的方法中使用instance,所以instance的声明应该是静态的
		}

		}
		return instance;
	}
}

存在的问题:
每当一个线程进入到同步代码块,另一个线程都需要等待这个线程执行整个代码块完全,释放锁资源。即使对象实例已经存在,instance已经不为空,仍然要等待线程释放锁资源。也就是说,每一次(不管是第几次)获取对象实例,只要有线程进入同步代码块,那么就需要等待,十分消耗时间。

解决方法:
只需要当对象实例存在了,那么就不再需要进入同步代码块即可。采用双重锁即可。

4、懒汉模式(线程安全优化,双重锁)

class Order{
	//1、私有化类的构造器
	private Order() {}
	//2、声明类的对象,不初始化
	private static Order instance = null;
	//3、声明一个public的static的返回当前对象的方法
	public static Order getInstance() {
		if(instance==null){//7.如果对象实例已经存在,那么就不需要在进入同步代码块
			//6.为了解决线程安全问题,通过一个同步锁,锁住代码块,只要一个线程进入同步代码块中没有执行完整个代码块,那么就没有线程可以进入代码块,也就不能通过if语句。也就是说,不会出现两个线程均在if判断内。
			synchronized(Order.class){
				if(instance == null) {//5、如果每次调用方法都 new 一个对象,那么就违背了单例模式只能创建一个对象的初衷,所以加一个null判断			
				instance = new Order();//4、由于要在静态的方法中使用instance,所以instance的声明应该是静态的
				}

			}
		}
		return instance;
	}
}

三、饿汉模式和懒汉模式的分析
饿汉模式:
优点:天生线程安全;
缺点:在加载时就创建对象实例(加载对象的时间很长)
懒汉模式:
优点:延迟对象的创建,当调用方法获取对象的时候才创建对象
缺点:本来是线程不安全的,需要解决线程安全问题。

四、单例设计模式的应用场景
单例模式的优点:由于单例模式只生成一个实例,减少系统的开销,当一个对象的产生需要较多的资源时,例如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
举例:java.lang.Runtime
应用场景:
网站计数器
应用程序日志应用
数据库连接池
项目中读取配置文件的类
Application也是单例的典型应用
Windows的Task Manager(任务管理器)就是很典型的单例模式。
Windows的Recycle Bin(回收站)也是典型的单例应用。
servlet也是单例的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值