标签:
保证一个类只有一个实例,并且提供了访问该实例的全局访问点
主要
饿汉式:线程安全,调用效率高。但是不能延时加载
懒汉式:线程安全,调用效率不高。但是可以延迟加载
其它:
双重检锁式:由于JVM底层内部模型的原因,偶尔会出现问题,不建议使用
静态内部类式:线程安全,调用效率高,而且可以延迟加载
枚举单例:线程安全,调用效率高,不可延迟加载
饿汉式的示例代码:
public class Singleton01 { //类初始化的时候,立即加载这个对象(没有延时加载的优势)。加载类时,是线程安全的 private static Singleton01 instance = new Singleton01(); private Singleton01(){} //方法没有同步调用效率高 public static Singleton01 getInstance(){ return instance; } }
饿汉式单例模式的代码中,static变量会在类装载的时候进行初始化,此时不会涉及到多个线程对象访问该对象的问题。虚拟机会保证只会装载一次该类,肯定不会发生并发访问的问题,因此可以省略synchronized关键字
问题:如果仅仅是加载本类,而不是要调用getInstance,甚至永远都没有调用,则会造成资源浪费。
懒汉式的示例代码
1 package com.chunjiangchao.pattern.singleton; 2 /** 3 * 测试懒汉式单例模式 4 */ 5 public class Singleton02 { 6 //类初始化的时候,不初始化这个对象(延时加载,真正用的时候再创建)。 7 private static Singleton02 instance = null; 8 private Singleton02(){} 9 ////方法同步,调用效率低! 10 public static synchronized Singleton02 getInstance(){ 11 if(instance == null) 12 instance = new Singleton02(); 13 return instance; 14 } 15 }
要点:延迟加载,懒加载真正用到的时候才会选择加载
问题:
资源利用率高了,但是每次调用getInstance()方法都要同步,并发效率较低。
双重检锁实现
1 package com.chunjiangchao.pattern.singleton; 2 /** 3 * 测试DCL(双重检锁)单例模式 4 * 5 */ 6 public class Singleton03 { 7 //类初始化的时候,不初始化这个对象(延时加载,真正用的时候再创建)。 8 private volatile static Singleton03 instance = null; 9 private Singleton03(){} 10 ////代码块同步,调用效率要比同步方法要快一些,由于JVM的原因在高并发的情况下会出现问题 11 public static Singleton03 getInstance(){ 12 if(instance == null){ 13 synchronized (Singleton03.class) { 14 if(instance == null) 15 instance = new Singleton03(); 16 } 17 } 18 return instance; 19 } 20 }
提高了执行 的效率,不必每次获取对象的时候都要进行同步,只有第一次才会进行同步创建。
问题:
由于编译器优化的原因和JVM底层内部模型原因,偶尔会出现问题,不建议使用。但是我们可以在instance前面添加volatile关键字,这样就没问题了。
静态内部类实现方式:(懒加载方式)
1 package com.chunjiangchao.pattern.singleton; 2 /** 3 * 静态内部类单例模式 4 * 这种方式:线程安全,调用效率高,并且实现了延时加载! 5 */ 6 public class Singleton04 { 7 private Singleton04(){} 8 public static Singleton04 getInstance(){ 9 return Inner.instance; 10 } 11 private static class Inner{ 12 private static final Singleton04 instance = new Singleton04(); 13 } 14 }
外部类没有static属性,则不会像饿汉式那样,上来就把对象造出来了
只有真正调用getInstance才会加载静态内部类。加载类时是线程安全的。instance 是static final类型,保证了内存中只有这样一个实例存在,而且只被赋值一次,从而保证了线程安全性。
兼并并发高效调用和延迟加载的优势。
换一句户说:静态内部有具备饿汉式和延迟加载的优势。
枚举实现单例:
1 package com.chunjiangchao.pattern.singleton; 2 /** 3 * 枚举式实现单例模式(没有延时加载) 4 */ 5 public enum Singleton05 { 6 instance;//这个枚举元素,本身就是单例对象! 7 public void operation(){ 8 //添加需要的操作 9 } 10 }
优点:实现简单;枚举本身就是单例。由JVM从根本上提供保障。避免反射和序列化的漏洞
缺点:无延迟加载
单例对象占用资源少,不需要延迟加载:
枚举好于饿汉式
单例对象占用资源大,需要延迟加载
静态内部类好于懒汉式
6.问题
反射可以破解上面(不包含枚举)的实现方式(防止的做法是在构造方法中手动抛出异常)
反序列化可以破解(不包含枚举)的实现方式
可以通过定义readResolve防止获得不同对象。反序列化的时候,如果对象所在的类定义了readResolve()方法(一种回调方法),返回自己创建的那个对象。
标签:
原文地址:http://www.cnblogs.com/chun-jiang-chao-de-gu-shi/p/5376574.html