java 单例模式5种写法
学习整理
饱汉模式(懒汉模式)
1 // 饱汉 2 // UnThreadSafe 3 public class Singleton1 { 4 private static Singleton1 singleton = null; 5 private Singleton1() { 6 } 7 public static Singleton1 getInstance() { 8 if (singleton == null) { 9 singleton = new Singleton1(); 10 } 11 return singleton; 12 } 13 }
优点:懒加载启动快,资源占用小,使用时才实例化,无锁。
缺点:非线程安全。
饱汉模式(懒汉模式)--线程安全
1 public class Singleton { 2 3 /** 4 * 定义一个变量来存储创建好的类实例 5 */ 6 7 private static Singleton uniqueInstance = null; 8 9 /** 10 * 私有化构造方法,好在内部控制创建实例的数目 11 */ 12 13 private Singleton(){ 14 } 15 16 /** 17 * 定义一个方法来为客户端提供类实例 18 * @return 一个Singleton的实例 19 */ 20 21 public static synchronized Singleton getInstance(){ 22 23 //判断存储实例的变量是否有值 24 if(uniqueInstance == null){ 25 //如果没有,就创建一个类实例,并把值赋值给存储类实例的变量 26 uniqueInstance = new Singleton(); 27 } 28 29 //如果有值,那就直接使用 30 return uniqueInstance; 31 } 32 33 /** 34 * 示意方法,单例可以有自己的操作 35 */ 36 37 public void singletonOperation(){ 38 39 //功能处理 40 41 } 42 43 /** 44 * 示意属性,单例可以有自己的属性 45 */ 46 47 private String singletonData; 48 49 /** 50 * 示意方法,让外部通过这些方法来访问属性的值 51 * @return 属性的值 52 */ 53 54 public String getSingletonData(){ 55 56 return singletonData; 57 58 } 59 60 }
优点:同上,但加锁了。
缺点:synchronized 为独占排他锁,并发性能差。即使在创建成功以后,获取实例仍然是串行化操作。
饱汉模式(懒汉模式)--双重加锁检查DCL(Double Check Lock)
1 public class Singleton { 2 3 /** 4 * 对保存实例的变量添加volatile的修饰 5 */ 6 7 private volatile static Singleton instance = null; 8 9 private Singleton(){ 10 11 } 12 13 public static Singleton getInstance(){ 14 15 //先检查实例是否存在,如果不存在才进入下面的同步块 16 17 if(instance == null){ 18 19 //同步块,线程安全的创建实例 20 21 synchronized(Singleton.class){ 22 23 //再次检查实例是否存在,如果不存在才真的创建实例 24 25 if(instance == null){ 26 27 instance = new Singleton(); 28 29 } 30 31 } 32 33 } 34 35 return instance; 36 37 } 38 39 }
优点:懒加载,线程安全。
注:实例必须有 volatile 关键字修饰,其保证初始化完全。
饿汉模式
1 public class Singleton { 2 3 //4:定义一个静态变量来存储创建好的类实例 4 5 //直接在这里创建类实例,只会创建一次 6 7 private static Singleton instance = new Singleton(); 8 9 //1:私有化构造方法,好在内部控制创建实例的数目 10 11 private Singleton(){ 12 13 } 14 15 //2:定义一个方法来为客户端提供类实例 16 17 //3:这个方法需要定义成类方法,也就是要加static 18 19 //这个方法里面就不需要控制代码了 20 21 public static Singleton getInstance(){ 22 23 //5:直接使用已经创建好的实例 24 25 return instance; 26 27 } 28 29 }
优点:饿汉模式天生是线程安全的,使用时没有延迟。
缺点:启动时即创建实例,启动慢,有可能造成资源浪费。
Holder模式
1 public class Singleton { 2 /** 3 * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 4 * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载 5 */ 6 private static class SingletonHolder{ 7 /** 8 * 静态初始化器,由JVM来保证线程安全 9 */ 10 private static Singleton instance = new Singleton(); 11 } 12 /** 13 * 私有化构造方法 14 */ 15 private Singleton(){ 16 } 17 public static Singleton getInstance(){ 18 return SingletonHolder.instance; 19 } 20 }
优点:将懒加载和线程安全完美结合的一种方式(无锁)。(推荐)
备注:
1. 全局共享,独一份;
2. 构造函数不暴露(如果暴露便不能保证一份),自己负责自己的构造;
3. 懒汉式:Lazy load,用到才加载,非线程安全。如何保证线程安全呢:
(1) synchronized getInstance()。
(2)双重检查加锁(volatile)。
4. 饿汉式:一开始就申请好,浪费了点资源,但其线程安全。
5. Holder模式:
(1)改成内部类,由JVM保证线程安全性。