`

性能优化开始 设计优化 -- 单例模式

阅读更多

性能优化

优化分为:设计调优,代码调优,JVM调优,数据库调优,操作系统调优

 

设计优化:

软件的结构对于系统的整体性能有着重要的影响。优秀的设计结构可以规避很多潜在的性能问题,对系统性能的影响可能远远大于代码的优化。因此需要了解常用的设计模式,组件和设计方法。

 

善用设计模式

单例模式

确保系统中一个类只产生一个实例,好处是:

对于频繁使用的对象,可以省略创建对象所花费的时间,这对于重量级对象而言,是非常可观的一笔开销;new的次数减少,对系统内存的使用频率也会降低,将减轻GC的压力,缩短GC停顿的时间。

 

简单的实例:

public class Singleton{
	private Singleton(){
		System.out.println("Singleton is created");//创建单例的过程可能会比较慢,因为多
		//是重量级或占资源较多的对象
	}
	private static Singleton instance = new Singleton();
	public static Singleton getInstance(){
		return instance;
	}
}

 

单例类中必须要有private的构造函数。instance和get方法必须是static的。

上面这种单例模式实现方式非常简单,而且十分可靠。它唯一的不足是无法对instance实例做延迟加载。假如创建单例的过程非常慢,而由于instance成员变量是static的,因此在JVM加载单例类时,单例对象就会被建立,如果此时单例类在系统中还扮演其他的角色,那么在任何使用这个单例类的地方都会初始化这个单例变量,而不管是否会被用到,当创建实例很耗时时,会降低系统的性能。例如,单例类作为String工厂,用于创建一些字符串(既用于创建单例singleton,又用于创建String对象)

 

public class Singleton{
	private Singleton(){
		System.out.println("Singleton is created");
	}
	private static Singleton instance = new Singleton();
	public static Singleton getInstance(){
		return instance;
	}
	public static void createString(){
		System.out.println("createString in Singleton");
	} 
}

 

当调用createString()时,输出为:

Singleton is created

createString in Singleton

 

为了让instance在我们需要的时候创建出来,并以此提高系统在相关函数调用时的反应速度,就需要引入延迟加载机制。

 

public class LazySingleton{
	private LazySingleton(){
		System.out.println("LazySingleton is created");
	}
	private LazySingleton instance = null;
	public static synchronized LazySingleton getInstance(){
		if(null == instance){
			instance=new LazySingleton();
		}
		return instance;
	}
}

 

 

上面的单例实现,虽然实现了延迟加载的功能,但和第一种方法比,它引入了同步关键字,因此在多线程的环境中,它的耗时要远远大于第一种。

 

public void run(){
	long beginTime = System.currentTimeMillis();
	for(int i=0;i<100000;i++){
		Singleton.getInstance();
		//LazySingleton.getInstance();
	}
	System.out.println(System.currentTimeMillis()-beginTime);
}

 

开启5个线程运行,在我的电脑上,第一个要接近0ms,第二个接近100ms。

 

为了使用延迟加载引入的同步关键字反而减低了系统的性能,但可以进行如下的改进:

 

public class StaticSingleton{
	private StaticSingleton(){
		System.out.println("StaticSingleton is created");
	}
	private static class SingeltonHolder{
		private static StaticSingleton instance = new StaticSingleton();
	}
	public static StaticSingleton getInstance(){
		return SingeltonHolder.instance;
	}
}

 

这个实现是使用内部类来维护单例的实例,当StaticSingleton被加载时,其内部并不会被初始化,所以当JVM加载StaticSingleton时,单例类并不会被实例化,但调用getInstance被调用的时候,才会加载SingeltonHolder,从而初始化实例。由于实例是在类加载是完成的,所以对线程是友好的。这是比较完善的实现。

 

基本上,用上面的方法可以实现单例。但有例外情况,如利用反射强行调用单例类的私有构造函数,生成多个单例。不过这里会有另外一种情况。

public class SerSingleton implements java.io.Serializable{
	String name;
	private SerSingleton(){
		System.out.println("SerSingleton is created");
		name="SerSingleton";
	}
	private static SerSingleton instance = new SerSingleton();
	public static SerSingleton getInstance(){
		return instance;
	}
	public static void createString(){
		System.out.println("createString in SerSingleton");
	}
	private Object readResolve(){
	//组织生成新的实例,总是返回当前的对象
	return instance;
	}
}

 

 

测试代码:

@Test
public void test() throws Exception{
	SerSingleton s1 = null;
	SerSingleton s = SerSingleton.getInstance();
	FileOutputStream fos = new FileOutputStream("SerSingleton.txt");
	ObjectOutputStream oos = new ObjectOutputStream(fos);
	oos.writeObject(s);
	oos.flush();
	oos.close();
	FileInputStream fis = new FileInputStream("SerSingleton.txt");
	ObjectInputStream ois = new ObjectInputStream(fis);
	s1 = (SerSingleton)ois.readObject();
	Assert.assertEquals(s,s1);
}

 

 

当去掉readResolve()方法时,测试会出错,说明s和s1指向了不同的实例。在反序列化后,生成多个实例。

而加上readResolve()方法后,程序正常退出,说明即使经过反序列化,仍然保持了单例的特征。

事实上,在实现了私有的readResolve后,readObject()就已经形同虚设,直接使用readResolve()来替换原来的返回值,从而在形式上构造了单例。

序列化和反序列化可能会破坏单例。一般来说,对单例进行序列化和反序列化的场景不多见,若存在,要多加注意。

 

分享到:
评论

相关推荐

    单例模式---初学 优点--缺点

    单例模式是软件设计模式中的一种经典模式,主要用于限制类的实例化,确保在整个应用程序中,该类只有一个实例...在Java等语言中,可以使用双重检查锁定、静态内部类等策略优化单例模式的实现,以兼顾性能和线程安全性。

    PHP5设计模式-单例模式

    **PHP5设计模式 - 单例模式** 单例模式是一种常用的设计模式,它在软件工程中扮演着控制类实例化过程的角色,...在实际开发中,应根据项目的具体需求权衡是否使用,以及如何优化单例模式以适应不断变化的软件需求。

    设计模式——单例模式

    为了解决懒汉式单例模式的性能问题,有几种优化策略: 1. **双检锁/双重校验锁(DCL,即 double-checked locking)** ```java public class Singleton { private volatile static Singleton instance; private ...

    单例模式----数据库连接池管理类的应用

    单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供一个全局访问点。在IT行业中,尤其是在处理资源密集型任务如数据库连接时,单例模式被广泛应用。数据库连接池就是这种应用的一个典型例子。 ...

    单例设计模式的优缺点和设计思想

    2. **性能提升**:单例模式通过避免重复实例化同一对象,减少了性能上的开销,尤其是在频繁调用相同功能的情况下,可以显著提高系统的响应速度。 3. **资源管理**:单例模式可以有效地避免对资源的多重占用,例如...

    设计模式之单例模式(结合工厂模式)

    单例模式是软件设计模式中的一种经典模式,它保证了类只有一个实例存在,并提供一个全局访问点。在Java等面向对象编程语言中,单例模式常用于管理共享资源,如数据库连接池、线程池或者配置文件等。结合工厂模式,...

    23钟设计模式之单例模式

    总结来说,单例模式在Java中的实现涉及到多线程同步、内存模型以及性能优化等多个方面。理解并熟练掌握各种单例模式的实现方式,有助于我们编写出更加健壮、高效的代码。同时,设计模式的应用不仅仅局限于单例,还有...

    java单例设计模式的好处

    单例设计模式是软件开发中一种重要的设计模式,它的核心思想是确保一个类只有一个实例...总的来说,单例模式在控制对象生命周期、优化资源使用和简化系统结构方面都有显著作用,是Java程序员应掌握的重要设计模式之一。

    java 设计模式 mvc模式 单例模式 代理 工厂 简单工厂 第二部分

    本篇将深入探讨标题中提及的几种设计模式:Model-View-Controller(MVC)模式、单例模式、代理模式以及工厂模式,尤其是简单工厂模式。 **1. Model-View-Controller (MVC) 模式** MVC模式是一种架构模式,它将应用...

    单例设计模式.pdf

    在选择单例模式的实现方式时,需要考虑性能、内存使用和线程安全等因素,根据具体的应用场景和需求进行选择。在多线程环境中,确保线程安全是至关重要的,而性能则可能需要在不同实现之间权衡。

    三种工厂设计模式和两种单例模式

    在本文中,我们将深入探讨三种工厂设计模式——简单工厂模式、抽象工厂模式和工厂方法模式,以及两种单例模式——饿汉单例模式和懒汉单例模式。这些模式都是面向对象设计中的重要组成部分,对于理解和构建可维护、可...

    JavaScript设计模式---单例模式详解【四种基本形式】

    以上四种单例模式在JavaScript中都有其适用的场景,开发者可以根据实际需求选择合适的设计模式。单例模式在JavaScript中的应用广泛,比如管理DOM元素、提供全局配置、控制页面的公共资源等。理解并熟练运用单例模式...

    连接数据库单例模式

    1. **资源优化**:由于单例模式保证了数据库连接的唯一性,可以减少不必要的连接创建与销毁,从而降低了资源消耗。 2. **简化编程**:通过全局访问点获取数据库连接,简化了代码编写过程。 3. **提高性能**:减少了...

    单例模式详解~~单例模式详解~~

    单例模式是一种设计模式,它的主要目标是确保一个类只有一个实例,并提供一个全局访问点。在软件工程中,单例模式常用于控制资源的共享,比如数据库连接池、线程池或者日志系统等,这些资源通常需要全局唯一且高效地...

    Java单例模式设计

    Java单例模式是一种常用的设计模式,它保证一个类只有一个实例,并提供全局访问点。这种模式在需要频繁创建和销毁对象的场景中,或者当对象昂贵时(如数据库连接),能够节省系统资源,提高效率。本篇文章将深入探讨...

    单例模式详解

    单例模式(Singleton Pattern)是一种常用的软件设计模式,属于创建型模式之一。其目的是确保某个类只有一个实例,并提供一个全局访问点。单例模式的核心在于确保在系统运行期间一个类只能有一个实例存在。 #### 二...

    Qt qml Singleton 单例模式

    在Qt的Qml环境中,单例模式是一种设计模式,它允许在整个应用程序中创建一个全局访问点,确保某个类只有一个实例存在。这样的设计模式在需要共享数据或者服务时非常有用,避免了多处创建相同对象导致的数据不一致或...

    单例模式.ppt

    【单例模式】是一种常用的软件设计模式,其主要目的是确保一个类只有一个实例,并提供一个全局访问点。在软件开发中,单例模式常用于管理共享资源或者需要协调多个组件交互的场景,比如数据库连接池、日志服务等。 ...

    java单例设计模式-饿汉式-懒汉式[参照].pdf

    在Java中,单例模式有两种常见的实现方式:饿汉式和懒汉式。 1. **饿汉式**: 饿汉式单例在类加载时即创建了实例,因此它是线程安全的。这种方式保证了类加载后就立即初始化单例对象,避免了多线程环境下的同步...

Global site tag (gtag.js) - Google Analytics