单例模式
一、单例模式简介
单例模式(Singleton),也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。
二、单例模式的运用场景:
1.外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。
2. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗
3. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。
三、实现单例模式的方法思路:
一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名 称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们 还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。
四、实现单例模式的方式
1、饿汉单例式:
天生线程安全。
1 package com.demo.study.singleton; 2 //饿汉模式:在类初始化时,已经自行实例化,而且线程天生安全 3 public class Singleton3 { 4 5 private Singleton3(){} 6 public static final Singleton3 singleton3 = new Singleton3(); 7 8 public static Singleton3 getInstance(){ 9 return singleton3; 10 } 11 }
2、懒汉单例式:
懒汉模式线程是不安全的,故需要加线程锁来实现同步,可以用以下两种同步方式:
第1种,同步方法方式,每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的;
第2种,同步代码块方式,在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗。
①、同步方法方式
1 package com.demo.study.singleton; 2 3 public class Singleton2 { 4 //将构造器定义为私有的,其他类则无法通过构造器获得该类的实例 5 private Singleton2(){} 6 public static Singleton2 singleton = null; 7 8 public static synchronized Singleton2 getInstance(){ 9 if(singleton == null) 10 singleton = new Singleton2(); 11 return singleton; 12 } 13 }
②、同步代码块方式
1 package com.demo.study.singleton; 2 //同步代码块的方式(懒汉模式) 3 public class Singleton { 4 5 //将构造器定义为私有的,其他类则无法通过构造器获得该类的实例 6 private Singleton() {} 7 8 //在此将该属性设置为private,那么singleton只能通过下面的方法获取 9 private static Singleton singleton = null; 10 11 public static Singleton getInstance() { 12 if (singleton == null) { 13 synchronized (Singleton.class) { 14 if (singleton == null) 15 singleton = new Singleton(); 16 } 17 } 18 return singleton; 19 } 20 }
3、静态内部类的方式
1 package com.demo.study.singleton; 2 //用静态内部类的方式实现单例 3 public class StaticInnerClass { 4 5 private StaticInnerClass(){} 6 //静态内部类 7 private static class SingletonInstance{ 8 static SingletonInstance singletonInstance = new SingletonInstance(); 9 } 10 11 public static SingletonInstance getInstance(){ 12 return SingletonInstance.singletonInstance; 13 } 14 }
五、资源加载和性能区别:
饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,而懒汉式,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。静态内部类的方式资源利用率高,但第一次加载时反应不够快;java中饿单例模式性能优于懒单例模式,若对资源十分在意可以采用静态内部类。