单例模式以及使用单例模式的时候的代码优化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Phoenix_smf/article/details/82824377

参考文献:《Java程序性能优化》.葛一鸣

单例模式是最基础的设计模式之一,它是一种对象创建模式,用于产生一个对象的具体实例,他可以保证系统中一个类只产生一个实例,在java语言中,这样的行为能带来两大好处:
(1)对于频繁使用的对象,能够省略对象创建的时间,对于那些重量级对象而言,是一笔非常可观的系统开销。
(2)因为new的次数减少因此对于系统内存的使用频率也会降低,这会减轻GC(垃圾回收机制)的压力,缩短GC停顿时间。
因此,对于系统的关键组件以及被频繁使用的对象,使用单例模式,可以有效改善系统性能。

单例模式的参与者非常简单,只有单例类和使用者两个:

在这里插入图片描述

单例模式的核心在于通过一个借口返回唯一的对象实例。
下面一个简单的例子:

package com.example.demo;

/**
* @author 作者SMF:
* @version 创建时间:2018年9月23日 下午7:51:19
* 类说明
*/
public class Single {
	private  Single(){
		System.out.print("单例模式");
	}
	private static  Single instance = new Single();
	public static Single getInstance(){
		return instance;
	}
}

注意:单例类必须要有一个private级访问的构造函数,只有这样才能保证单例类不会再系统中的其它代码内被实例化,这点是很重要的,其次instance成员变量和gerInstance方法必须是static的。
这种实现方式非常简单,而且十分可靠,唯一的不足之处是无法对instance做延时加载。假如单例的创建过程很慢,而由于instance成员变量是static定义的,JVM在加载单例类的时候,单例对象也会被创建,如果此时该单例类还在系统中扮演其他角色,那么任何使用这个单例类的地方都会初始化这个单例变量,而不管是否会用到,比如单例类作为String工厂用于创建一些字符串(该单例类及用于创建Single对象,又用于创建Sting对象:)

package com.example.demo;

/**
* @author 作者SMF:
* @version 创建时间:2018年9月23日 下午7:51:19
* 类说明
*/
public class Single {
	//构造方法
	private  Single(){
		System.out.println("单例模式");
	}
	//内部静态变量
	private static  Single instance = new Single();
	//内部静态方法
	public static Single getInstance(){
		return instance;
	}
	//内部静态方法
	public static void  CreateString(){
		System.out.println("创建String");
	}
}

在直接执行Single.CreateString()方法的时候会输出:
在这里插入图片描述

可以看到虽然没有使用单例对象,但是他还是被创建出来了,解决方法是引入延时加载机制:

package com.example.demo;
/**
* @author 作者SMF:
* @version 创建时间:2018年9月25日 下午12:22:45
* 类说明
*/
public class LazySingleton {
	private LazySingleton(){
		System.out.println("单例创建");
	}
	private static LazySingleton instance = null;
	//懒加载机制
	public static synchronized LazySingleton getInstance(){
		if(instance == null){
			instance = new LazySingleton();
		}
		return instance;	
	}
}

但是上述代码中的懒加载加入了Synchronized关键字,同步的操作,因此在线程比较多的情况下,性能会降低许多,可以通过内部类的方式进一步优化:

package com.example.demo;
/**
* @author 作者SMF:
* @version 创建时间:2018年9月25日 下午1:34:03
* 类说明
*/
public class StaticSingleton {
	//使用内部类维护单例实例
	private static class Singleholder{
		private static StaticSingleton  instance = new StaticSingleton();
	}
	//获取实例对象
	public static StaticSingleton getInstance(){
		System.out.println("获取实例对象");
		return Singleholder.instance;
	}
	
	public static void createString(){
		System.out.println("创建String");
	}
}

这样单独使用CreateString()方法是不会加载单例类,只有使用了getInstance()方法的时候才创建单例类,而且多线程使用也不会造成大量的性能损耗。

另外还有特殊的序列化和反序列化的情况下会破坏单例,从而使系统中出现两个单例类的实例,那么解决方法是在单例类中增加一个 私有的readResolve()函数,可以防止生成新的单例对象,那么就是一个比较完善的单例对象了。

private Object readResolve(){
		return instance;
	}

猜你喜欢

转载自blog.csdn.net/Phoenix_smf/article/details/82824377