设计模式(单例模式)
一、简介
单例模式是设计模式中使用最普遍的一种设计模式,它是对象创建模式,用于产生一个对象的具体实例,
确保系统中一个类只有一个实例。
二、使用场景及优点
对于频繁使用的对象,可以省略创建对象花费的时间。同时由于new操作的吃书减少,因此对系统内存
的使用频率会降低,减轻了GC压力,缩短了GC停顿时间。
三、常见表现形式
1.在类加载时初始化单例属性(优点:效率较高,多线程安全;缺点:增多程序加载时的额外负载)
public class ServiceConnation1 { /** * 类加载时就实例化单例属性,此策略较为安全,多线程时不会产生多个实例。但是当被实例化的 * 类的构造方法需要做大量工作、或做者远程连接操作就会使得程序在启动时耗去很长的时间,致 * 使启动时间延长,用户体验降低。 */ private static ServiceConnation1 sc = new ServiceConnation1(); private InitialContext context; private ServiceConnation1() { try { /** * 此处并没有指定properties属性,只是示例简要的结构,模拟远程连接操作等 * 较为耗时的初始化代码,程序并不能运行成功。 */ context = new InitialContext(); } catch (NamingException e) { e.printStackTrace(); } } public static ServiceConnation1 getInstance() { return sc; } public Object getService(String name) throws NamingException { return context.lookup(name); } }
2.延迟加载策略(优点:减少程序加载时的负载;缺点:需要引入同步,效率低下)
public class ServiceConnation2 { private static ServiceConnation2 sc = null; private InitialContext context; private ServiceConnation2() { try { /** * 此处并没有指定properties属性,只是示例简要的结构,模拟远程连接操作等 * 较为耗时的初始化代码,程序并不能运行成功。 */ context = new InitialContext(); } catch (NamingException e) { e.printStackTrace(); } } public static synchronized ServiceConnation2 getInstance() { /** * 在调用方法是判断是否初始化单例对象,这样可以很好的解决上述启动耗时的问题,方法在不添 * 加同步关键字的时候,在非多线程运行下较为可靠,效率也较高。但是在多线程的情况下可能会 * 产生多个实例,因此需要给方法添加synchronized修饰,这样效率也大大降低了。 */ if(sc == null){ sc = new ServiceConnation2(); } return sc; } public Object getService(String name) throws NamingException { return context.lookup(name); } }
3.内部类延迟加载策略(改进前两种的缺点,推荐使用)
public class ServiceConnation3 { private InitialContext context; private ServiceConnation3() { try { /** * 此处并没有指定properties属性,只是示例简要的结构,模拟远程连接操作等 * 较为耗时的初始化代码,程序并不能运行成功。 */ context = new InitialContext(); } catch (NamingException e) { e.printStackTrace(); } } public static ServiceConnation3 getInstance() { /** * 为了解决因延长加载而带来的同步效率低下的问题,将程序改进为内部类的方式实例化单例对象 */ return ServiceConnationHolder.sc; } public Object getService(String name) throws NamingException { return context.lookup(name); } /** * ServiceConnationHolder为内部类,在程序初始化的收不会被加载,因此利用内部类的 * 这种特性可以实现延迟加载,同时又不存在多线程安全带的问题。 */ private static class ServiceConnationHolder { private static ServiceConnation3 sc = new ServiceConnation3(); } }
四、测试
public class ServiceConnation { private ServiceConnation() { try { System.out.println("************do inital something************"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } public static ServiceConnation getInstance() { return ServiceConnationHolder.instance; } public Object getService(String name) throws NamingException { System.out.println("************getService************"); return new Object(); } private static class ServiceConnationHolder{ public static ServiceConnation instance = new ServiceConnation(); } }
public class SingletonTest { @Test public void testInitalSingleton(){ ServiceConnation sc = ServiceConnation.getInstance(); try { sc.getService("beanName1"); sc = ServiceConnation.getInstance(); sc.getService("beanName2"); } catch (NamingException e) { e.printStackTrace(); } } }