单例模式简介

Java中很多设计模式。今天我们就来讲第一种常用的模式——单例设计模式。

单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。在服务器和浏览器端,我们也会使用单利设计模式来解决客户访问的问题。另外,单例是单例,但是,这一个单例可以被多访问的。这就涉及到了线程安全的问题。

单例设计模式的总方式是:

1. 把构造函数私有化

2. 本类中创建一个静态私有的本类的对象(也可以先是引用,之后才创建)

3. 提供一个公共静态的方法返回创建好的本类对象

下面就来介绍单例设计模式的两种方式:懒汉式和饿汉式。

懒汉式:

public class SingleText {
	//饿汉式
	private static SingleText s =null;
	private SingleText(){	
		System.out.println("单例被创建了");
	}
	public static SingleText returnSingle(){
		if (s==null) {//这里一定要加判断,不然单例模式没有用。
			s = new SingleText();
		}
		return s;
	}
	
	public void sup() {
		System.out.println("mmmm");
	}
	
	public static void main(String[] args) {
		SingleText s =SingleText.returnSingle();
		s.sup();
		SingleText s2 = SingleText.returnSingle();
		s2.sup();
		System.out.println(s==s2);
		
	}
}

上面的代码运行的结果:

单例被创建了
mmmm
mmmm
true

从第四行和第三行就知道,这个类只创建了一个对象。

但是懒汉式的方式存在线程安全的问题。

所以我们要加一个双重判断及同步代码块的机制:这种方式很常用。

 

public static SingleText returnSingle(){
		if (s==null) {
			synchronized(SingleText.class){
				if (s==null) {
					s = new SingleText();
				}
			}
		}
		return s;
	}

以上面的方式既可以保证线程安全,又能增加效率。

 

但是下面的方式比上面的方式更提高效率

使用静态内部类来创建单例的实例,在静态内部类创建实例,比上面双重判断加锁定效率更高。

这种方式利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗。

 

public class SingleText {
	//懒汉式,调用返回实例时才创建对象。
	private static class  InnerLoad{
		private static SingleText s = new SingleText();
	}
	
	public static SingleText returnSingle(){
		
		return InnerLoad.s;
	}
	public void sup() {
		System.out.println("mmmm");
	}
	
	public static void main(String[] args) {
		SingleText s1 = SingleText.returnSingle();
		s1.sup();
		SingleText s2 =SingleText.returnSingle();
		s2.sup();
		System.out.println(s1==s2);
	}
}

通过下面运行结果,我们也能推断出,这种方式也实现了单例模式。

 

mmmm
mmmm
true
 

懒汉式:

 

public class SingleText {
	//饿汉式,加载类时就已经实例化对象了
	private static SingleText s = new SingleText();
	private SingleText(){
		
	}
	
	public static SingleText returnSingle(){
		return s;
	}
	
	public void cry() {
		System.out.println("哇哇~~~~");
	}
	public static void main(String[] args) {
		SingleText s1 = SingleText.returnSingle();
		s1.cry();
		SingleText s2 = SingleText.returnSingle();
		s2.cry();
		System.out.println(s1==s2);
	}
}<strong>
</strong>

下面是运行结果:

 

哇哇~~~~
哇哇~~~~
true

恶汉式的单例设计模式是原本就具有线程安全性质的。所以不用考虑安全问题。