设计模式:单例模式
来源:互联网 发布:python爬取天气数据 编辑:程序博客网 时间:2024/05/17 03:02
1、懒汉式(线程不安全)
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}
在多线程模式会出现问题,在判断是否为空的情况下,假如一个线程进来,判断为空,还没new对象的时候,另外一个线程进来,也是为空,于是也进去new对象,所以导致获取的单例对象不同,产生线程安全问题。
2、懒汉式(线程安全)
public class Singleton { private static Singleton instance; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}
getInstance方法上面加了synchronized修饰,而且还是static方法,所以这里锁住的是当前类的class,所以能够保证线程安全,但是再所有调用Singleton.getInstance()的时候,都要给获取对象锁去操作,太耗性能。
3、饿汉式(线程安全)
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; }}
这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到lazy loading的效果。
4、饿汉式2(线程安全)
public class Singleton { private static Singleton instance = null; static { instance = new Singleton(); } private Singleton() { } public static Singleton getInstance() { return instance; }}
其实跟第三种差不多,static静态代码块也是在Singleton类加载的时候调用。
5、静态内部类(线程安全)
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton() { } public static final Singleton getInstance() { return SingletonHolder.INSTANCE; }}
这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。
6、枚举(线程安全)
public enum Singleton { INSTANCE;}
这种方式的好处主要是:1.线程安全 2.不会因为序列化而产生新实例 3.防止反射攻击
默认枚举实例的创建是线程安全的.(创建枚举类的单例在JVM层面也是能保证线程安全的),所以不需要担心线程安全的问题.
关于序列化.
以往的单例实现了序列化接口,那么就再也不能保持单例的状态了.因为readObject()方法一直返回一个
新的对象.使用radResolve()来避免此情况发生.
//readResolve to prevent another instance of Singletonprivate Object readResolve(){ return INSTANCE;}
参考:https://segmentfault.com/q/1010000000646806
7、双重校验锁(线程安全)
public class Singleton{ private static volatile Singleton INSTANCE; private Singleton(){} public static Singleton getInstance(){ if(INSTANCE == null){ synchronized(Singleton.class){ if(INSTANCE == null){ INSTANCE = new Singleton(); } } } return INSTANCE; }}
也就是第一种方式的线程安全版本,第二种方式的升级版,正如第一种方式而言,假设两个线程,一个线程判断为空,进入,还没赋值,另外一个线程判断为空,进入,但是只有一个线程能获取到当前类的class锁,所以其中一个线程进入赋值new对象,然后返回,这个同步块执行后,另外一个线程也拿到锁,进入,判断instance有值了,所以跳出if,return instance的值,这种方式还是比较好,注意这里修饰instance属性加了修饰符volatile
在JDK1.5之后,双重检查锁定才能够正常达到单例效果。因为volatile 是JDK1.5才开始提供的。
总结
其实总的来说,是五种写法:懒汉,恶汉,双重校验锁,枚举和静态内部类。
个人推荐,如果不在乎是否延迟加载的问题,可以使用第三种,简单粗暴,线程安全。第五种和第七种是主流的解决方式,第六种是非主流方式,优点是代码简短。
- 设计模式------单例模式
- 设计模式------单例模式
- 设计模式-单例模式
- 设计模式 - 单例模式
- 设计模式---单例模式
- 设计模式---单例模式
- 【设计模式】单例模式
- 设计模式-单例模式
- 设计模式----单例模式
- 设计模式--单例模式
- 设计模式-单例模式
- 设计模式-单例模式
- [设计模式] 单例模式
- 设计模式--单例模式
- 设计模式---单例模式
- 设计模式--单例模式
- 设计模式 -----单例模式
- 设计模式:单例模式
- 尾盘次新股杀跌
- BinderService简单应用
- Cannot retrieve metalink for repository: epel. Please verify its path and try again
- iOS8自定义Collection View Cell - Swift教程
- 连续签到奖励 数据库如何设计?
- 设计模式:单例模式
- Oracle数据库-建库、建表空间,建用户
- Mac下关于百度开发者中心认领应用
- 欧拉函数
- html5 video标签自定义控制条
- 控制台天涯看小说
- iOS 高级工程师是怎么进阶的(补充版20+点)
- 在CentOS 上安装EPEL源
- 查找两个字符串a,b中的最长公共子串