Design Pattern 1: Singleton
来源:互联网 发布:淘宝联盟卖家能看见吗 编辑:程序博客网 时间:2024/05/27 21:48
概念:单例模式确保某一个类只有一个实例,并且自行实例化向整个系统提供这个实例。
实现要点:
- 构造器声明为private来隐藏,防止其他类调用
- private static Singleton实例
- 获取实例方法声明为public来供系统调用
设计单例类的目标:
- 延迟加载-lazy loading
- 调用效率
- 线程安全
懒汉
可以达到lazy-loading,线程不安全,实际不会使用
public class Singleton1 { private static Singleton1 instance; private Singleton1(){} public static Singleton1 getInstance(){ if(instance == null){ instance = new Singleton1(); } return instance; }}
懒汉,线程安全
Singleton1的线程安全版本,虽然线程安全但是效率太低,实际中也不会使用,因为对象只有在初始化时需要同步,多数情况下并不需要互斥的获得对象,这种加锁方式会造成巨大无意义的资源消耗,Singleton7的双重校验锁方式对此进行了优化。
public class Singleton2 { private static Singleton2 instance; private Singleton2(){}; public static synchronized Singleton2 getInstance(){ if(instance == null){ instance = new Singleton2(); } return instance; }}
饿汉
没有做到lazy-loading,实际中这种方式会造成资源浪费,因为系统中很多的类的实例都不会用到,加载类时就实例化太浪费!但是这种方式是线程安全的。
public class Singleton3 { private static Singleton3 instance = new Singleton3(); private Singleton3(){} public static Singleton3 getInstance(){ return instance; }}//另一种方式public class Singleton4 { private static Singleton4 instance = null; static { instance = new Singleton4(); } private Singleton4(){} public static Singleton4 getInstance(){ return instance; }}
静态内部类
与上种方式的区别是加了个内部类,这样加载类时并不会实例化instance,只有显式的调用getInstance方法的时候才会实例化,巧妙利用了Java虚拟机的类加载机制,既做到了线程安全,有做到了lazy-loading,实际应用中这种方式是比较推荐的。
public class Singleton5 { private static class SingletonHolder{ private static Singleton5 INSTANCE = new Singleton5(); } private Singleton5(){} public static Singleton5 getInstance(){ return SingletonHolder.INSTANCE; }}
枚举方式
这种方式不仅避免多线程同步问题,还防止反序列化重新创建新的对象
public enum Singleton6 { INSTANCE; public void whateverMethod(){}}
双重校验锁
该方式确保了只有在初始化的时候需要同步,当初始化完成后,再次调用getInstance不会再进入synchronized块。(对Singleton2的改进)但这种方式也被很多人诟病,实际中依然不会采用。
注意这里的instance声明为volatile的必要性:
防止指令重排
由于初始化操作 instance=new Singleton()是非原子操作的,主要包含三个过程
1. 给instance分配内存
2. 调用构造函数初始化instance
3. 将instance指向分配的空间(instance指向分配空间后,instance就不为空了)
虽然synchronized块保证了只有一个线程进入同步块,但是在同步块内部JVM出于优化需要可能进行指令重排,例如(1->3->2),instance还没有初始化之前其他线程就会在外部检查到instance不为null,而返回还没有初始化的instance,从而造成逻辑错误。
变量可见性
volatile类型变量可以保证写入对于读取的可见性,JVM不会将volatile变量上的操作与其他内存操作一起重新排序,volatile变量不会被缓存在寄存器,因此保证了检测instance状态时总是检测到instance的最新状态。
public class Singleton7 { private volatile static Singleton7 instance; private Singleton7() { } public static Singleton7 getInstance() { if (instance == null) { synchronized (Singleton7.class) { if (instance == null) instance = new Singleton7(); } } return instance; }}
以上是实现单例的几种方式汇总,其实综上也能发现在实际中能够付诸使用的方式很少,我们这里更多的是从线程安全和lazy-loading的角度更好的理解和实现单例模式。
在Spring使用ThreadLocal解决线程安全问题。我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,为每个线程提供一个独立的变量副本——”以空间换时间”,这样有状态的Bean就可以在多线程中共享了。 在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简便,且拥有更高的并发性。
参考链接:
http://www.blogjava.net/kenzhh/archive/2013/03/15/357824.html
http://blog.csdn.net/neo_ustc/article/details/7913066
http://blog.csdn.net/jq_ak47/article/details/54894793
- Design Pattern 1: Singleton
- Design Pattern 8-singleton
- [Design Pattern]:Singleton
- design pattern : Singleton
- Design pattern--Singleton
- C++ Singleton design pattern
- java singleton design pattern
- Singleton Design Pattern
- Singleton Design Pattern
- SingleTon Design Pattern
- Design pattern: Singleton
- Design Pattern: Singleton 模式
- java design pattern - singleton
- Design Pattern:Singleton
- Design Pattern: Singleton 模式
- Singleton Design Pattern Tutorial
- Java Design Pattern: Singleton
- Design Pattern—Singleton
- Codeforces Round #436 (Div. 2) F. Cities Excursions
- shell编程基础
- JS提交中文encodeURI两次
- 简单icon设计--会话图标
- 补充一篇:Windows 下,对于Apache的配置
- Design Pattern 1: Singleton
- SpringMVC解决跨域问题
- c语言学习习题
- .Net 网站记事本
- 数字转人名币大写形式
- 博客index
- c++复习Return Passing
- sort命令中-h参数的小作用
- 修改Tomcat编码方式的两种方法