JAVA设计模式(四)——单例模式

1、单例模式定义

        什么是单例模式?单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间里面,该类只存在一个实例对象。这有点像一个国家只有一个国家主席的味道。

       在GoF对单例模式的定义中,它说:单例是保证一个类只有一个实例存在,同时提供能够对该实例加以访问的全局访问方法。


2、单例产生原因

        在应用开发中,我们究竟为什么会使用到单例模式呢?主要有两种大的情况需要讨论:

(1)、操作同一个对象。当我们操作同一个对象的时候,这个时候,我们需要使用到单例模式,比如在多个线程中,消耗同一个资源或者对象,比如我们常见的一个场景,就是售票系统。我们同时有多个售票窗口在售票,但是售票的时候是操作的同一个票源对象。

(2)、需要资源共享。在一些应用程序中,可能某一个对象,或者该对象中的某一个方法,需要被反复用到,那么这样的对象,应该是一个单例模式。或者我们在系统较大的时候,需要节约资源,我们也会采用单例模式共享部分资源对象。常见的比如网络请求是一个常用的,反复使用的方法模块。

       单例模式可以满足我们的需求,那么单例模式就派上了用场。


3、单例的分类

       单例模式,又因为其特性,被细分为三种情况:饿汉式,懒汉式,双重检查。

(1)、饿汉式,顾名思义就是说这个人饿了,不管三七二十一,一开始就要创建一个对象。

(2)、懒汉式,与饿汉式相对应,这个家伙比较懒惰,只有在需要的时候才开始创建对象,比较懒惰。

(3)、双重检查,这个是对懒汉式的一个优化,主要式应对多线程情况下未知情况,稍后我们会加以分析。


4、单例的实现

       单例的实现原理并不多,一共只有两条,只要围绕着这两个原理去写代码,出来的代码就会成为一个单例的模式:

(1)、构造方法私有化。构造方法私有化之后,别的类就不能在根据它产生实例对象,保证了对象的单一。

(2)、提供一个返回实例的方法。如果我们不能实例化对象,就需要这样的一个方法获取该类的实例对象,我们在这个方法中进行一些操作使其保证对象单一。


5、饿汉式举例

       这里我们给出一个饿汉式的具体实例代码,如下:

public class Person {
	
	public static final Person person = new Person(); 
	
	// 构造方法私有化
	private Person(){
		
	}
	
	// 提供一个全局的静态的获取实例的方法
	public static Person getPerson(){
		return person;
	}
}


6、懒汉式举例

       懒汉式上面已经介绍过,这里直接给出代码,如下:

public class Person {
	
	public static Person person; 
	
	// 构造方法私有化
	private Person(){
		
	}
	
	// 懒汉式
	public static Person getPerson(){
		if (person == null) {
			person = new Person();
		}
		return person;
	}
}

7、双重检查

       上面我们提到,双重检查式对懒汉式的一个优化与加强,那么我们为什么要对懒汉式优化呢?懒汉式究竟有什么地方不好呢?

       当我们在单一的线程中,运行上面的代码,无论饿汉或者是懒汉,都不会出现问题。但是在多线程的程序中,饿汉式依然能够保证一个实例,而懒汉就未必了。为什么呢?我们看提供person这个实例的getPerson()这个方法。如果我们在很短的时间,同时有多个线程进入到了if语句当中,那么就会产生两个不同的对象,怎么办呢?我们会想着将其使用同步方法,锁起来,先让一个线程执行,然后让剩下的线程去执行,这样就不会出现多个实例了。代码如下:

public class Person {
	
	public static Person person; 
	
	// 构造方法私有化
	private Person(){
		
	}
	
	// 提供一个同步的方法,主要解决多线程造成的问题
	public static synchronized Person getPerson(){
		if (person == null) {
			person = new Person();
		}
		return person;
	}
}

       然而,上面的代码并没有完全解决我们的问题,为什么呢?虽然我们能够避免因为多线程的缘故,产生多个不同的实例对象,但是在多并发的程序中,如果线程很多,会导致每个线程都需要等待,这样会造成程序的卡顿甚至崩溃,那么,我们该怎么解决呢?请看如下代码:

public class Person {
	
	public static Person person; 
	
	// 构造方法私有化
	private Person(){
		
	}
	
	// 提供一个同步的方法
	public static synchronized Person getPerson(){
		// 第一次检查
		if (person == null) {
			//对当前对象加锁
			synchronized (Person.class) {
				// 第二次检查
				if (person == null) {
					person = new Person();
				}
			}
		}
		return person;
	}
	
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值