单例模式singleton —— II
来源:互联网 发布:求数组最大最小值 编辑:程序博客网 时间:2024/06/05 08:44
单例模式singleton的7种方式
@sunRainAmazing
懒汉式
类描述: 懒汉式(线程不安全)[不可用]
* * 懒汉式 线程不安全 ---不建议使用(适合单线程) * 单例模式有一下特点: * 1、单例类只能有一个实例。 * 2、单例类必须自己自己创建自己的唯一实例。 * 3、单例类必须给所有其他对象提供这一实例。 * * 只能在单线程下使用。如果在多线程下, * 一个线程进入了if (singleton == null)判断语句块, * 还未来得及往下执行,另一个线程也通过了这个判断语句, * 这时便会产生多个实例。所以在多线程环境下不可使用这种方式。
package sun.rain.amazing.singleton;/** * Created by sunRainAmazing on SUN_RAIN_AMAZING * @author sunRainAmazing */public class Singleton { //1 创建公有 静态单例变量 public static Singleton INSTANCE = null; //2 私有化构造器 private Singleton01_lazy(){ } //3 提供外部调用方法--因为是静态属性 故声明为静态方法 public static Singleton getInstance(){ //判断是否已创建---确保只创建一次 if(INSTANCE == null){ INSTANCE = new Singleton(); } return INSTANCE; }}
懒汉式 (同步方法)
类描述:懒汉式(线程安全,同步方法)[不推荐用]
* * 懒汉式 升级版 加同步锁 ---解决线程不安全问题,不推荐使用 * 做个线程同步就可以了,于是就对getInstance()方法进行了线程同步。 * * 缺点:效率低,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。 * 而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。 * 而无需再if判断了 方法进行同步效率太低要改进。
package sun.rain.amazing.singleton;/** * Created by sunRainAmazing on SUN_RAIN_AMAZING * @author sunRainAmazing */public class Singleton { private static Singleton INSTANCE; private Singleton(){} //添加关键字 同步锁synchronized //静态工厂方法 public static synchronized Singleton getInstance() { if (INSTANCE == null) { INSTANCE = new Singleton(); } return INSTANCE; } }
懒汉式 ( 同步代码块)
* 类描述 : 懒汉式(线程安全,同步代码块)[不可用]
* 由于Singleton.java同步方法 实现方式同步效率太低, * 所以摒弃同步方法,改为同步产生实例化的的代码块。 * 但是这种同步并不能起到线程同步的作用。 * 跟Singleton01_lazy.java实现方式遇到的情形一致, * 假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行, * 另一个线程也通过了这个判断语句,这时便会产生多个实例。
package sun.rain.amazing.singleton;/** * Created by sunRainAmazing on SUN_RAIN_AMAZING * @author sunRainAmazing */public class Singleton { private static Singleton INSTANCE; private Singleton01_lazyUpup() { } public static Singleton01_lazyUpup getInstance() { if (INSTANCE == null) { synchronized (Singleton.class) { INSTANCE = new Singleton(); } } return INSTANCE; }}
饿汉式
* 类描述: 饿汉式(静态常量)[可用]
* * 优点:这种写法比较简单,就是在类装载的时候就完成实例化。 * 避免了线程同步问题。 * 缺点:在类装载的时候就会完成实例化,没有达到Lazy Loading的效果。 * 如果从始至终从未使用过这个实例,则会造成内存的浪费。
package sun.rain.amazing.singleton;/** * Created by sunRainAmazing on SUN_RAIN_AMAZING * @author sunRainAmazing */public class Singleton { /*注意 这里声明为 final static ,下面这个可以不加final, 因为静态方法只在编译期间执行一次初始化, 也就是只会有一个对象。*/ private final static Singleton INSTANCE = new Singleton(); private Singleton(){} //静态工厂方法 public static Singleton getInstance(){ return INSTANCE; }}
饿汉式(静态代码块)
* 类描述:饿汉式(静态代码块)[可用]
* 优缺点与 上例 Singleton.java 静态常量方式 一致
package sun.rain.amazing.singleton;/** * Created by sunRainAmazing on SUN_RAIN_AMAZING * @author sunRainAmazing */public class Singleton { private static Singleton INSTANCE; /* * 在静态代码块中进行初始化 * --- 在类装载的时候,就执行静态代码块中的代码,初始化类的实例 */ static { INSTANCE = new Singleton(); } private Singleton() {} public Singleton getInstance() { return INSTANCE; }}
饿汉式(静态内部类)
* 类描述 : 静态内部类 [推荐用]
* 这种方式跟饿汉式方式采用的机制类似,但又有不同。 * 两者都是采用了类装载的机制来保证初始化实例时只有一个线程。 * * 不同的地方在饿汉式方式是只要Singleton类被装载就会实例化, * 没有Lazy-Loading的作用, 而静态内部类方式 * 在Singleton类被装载时并不会立即实例化, * 而是在需要实例化时,调用getInstance方法, * 才会装载SingletonInstance类,从而完成Singleton的实例化。 * * 类的静态属性只会在第一次加载类的时候初始化, * 所以在这里,JVM帮助我们保证了线程的安全性, * 在类进行初始化时,别的线程是无法进入的。 * * 优点:避免了线程不安全,延迟加载,效率高。
package sun.rain.amazing.singleton;/** * Created by sunRainAmazing on SUN_RAIN_AMAZING * @author sunRainAmazing */public class Singleton { /** * 私有化构造方法 */ private Singleton() { } /** * 类描述 静态内部类 * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载 */ private static class StaticInnerClass { // 创建 静态 final 属性 // 静态初始化器,由JVM来保证线程安全 private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return StaticInnerClass.INSTANCE; }}
/* * 这种方式是Singleton类虽然被装载了,但instance不一定被初始化。 * 因为StaticInnerClass类没有被主动使用,只有显示通过调用getInstance方法时, * 才会显示装载StaticInnerClass类,从而实例化instance。 * * 也就是说,当实例化instance很消耗资源,想让它延迟加载, * 另外一方面,又不希望在 Singleton类加载 时就实例化, * 因为我不能确保 Singleton类 * 还可能在其他的地方被主动使用从而被加载, * 那么这个时候实例化instance显然是不合适的。 * * 因此需要这种静态内部类的方式 来调配 */
枚举单例
类描述 :枚举 [推荐用]—-不建议使用 除非特殊情况
这种方式是Effective Java作者Josh Bloch 提倡的方式, * 它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象, * 可谓是很坚强的壁垒 * * 借助JDK1.5中添加的枚举来实现单例模式。 * 不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。 * 可能是因为枚举在JDK1.5中才添加,所以在实际项目开发中,很少见人这么写过。 * 优点 * 系统内存中该类只存在一个对象,节省了系统资源, * 对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。 * * * 缺点 * 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法, * 而不是使用new,可能会给其他开发人员造成困扰, * 特别是看不到源码的时候。 * * 适用场合 * 需要频繁的进行创建和销毁的对象; * 创建对象时耗时过多或耗费资源过多,但又经常用到的对象; * 工具类对象; * 频繁访问数据库或文件的对象。
package sun.rain.amazing.singleton;/** * Created by sunRainAmazing on SUN_RAIN_AMAZING * @author sunRainAmazing */public enum Singleton { INSTANCE; public void doWhateverMethod() { }}
双重锁单例
类描述 : 双重检查[推荐用] 双重校验锁
* 最推荐的使用方式是 静态内部类加载 和 双重校验 * 饿汉式 也可以使用 * * 在JDK1.5之后,双重检查锁定才能够正常达到单例效果。
package sun.rain.amazing.singleton;/** * Created by sunRainAmazing on SUN_RAIN_AMAZING * @author sunRainAmazing */public class Singleton { private static volatile Singleton SINGLETON; private Singleton() { } public static Singleton getInstance() { if (SINGLETON == null) { synchronized (Singleton.class) { if (SINGLETON == null) { SINGLETON = new Singleton(); } } } return SINGLETON; }}
/*关于双重锁定,建议你看看EhCache的源代码里的CacheManager类, * new了新的实例后,应该在synchronized块内return * 附部分源代码: */
public static CacheManager create() throws CacheException { if (singleton != null) { return singleton; } synchronized (CacheManager.class) { if (singleton == null) { LOG.debug("Creating new CacheManager with default config"); singleton = new CacheManager(); } else { LOG.debug("Attempting to create an existing singleton. Existing singleton returned."); } return singleton; // 这里是在synchronized块内返回的,而上述的例子不是 } }
有两个问题需要注意:
单例是五种写法。懒汉,恶汉,双重校验锁,枚举和静态内部类。
1.如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。 假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类装载器, 这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。
2.如果Singleton实现了java.io.Serializable接口, 那么这个类的实例就可能被序列化和复原。 不管怎样,如果你序列化一个单例类的对象, 接下来复原多个那个对象,那你就会有多个单例类的实例。
对第一个问题修复的办法是:
Java代码
private static Class getClass(String classname) throws ClassNotFoundException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if(classLoader == null) classLoader = Singleton.class.getClassLoader(); return (classLoader.loadClass(classname)); } }
对第二个问题修复的办法是:
Java代码
public class Singleton implements java.io.Serializable { public static Singleton INSTANCE = new Singleton(); protected Singleton() { } private Object readResolve() { return INSTANCE; } }
什么是线程安全?
如果你的代码所在的进程中有多个线程在同时运行, 而这些线程可能会同时运行这段代码。 如果每次运行结果和单线程运行的结果是一样的, 而且其他的变量的值也和预期的是一样的,就是线程安全的。 或者说:一个类或者程序所提供的接口对于线程来说是原子操作, 或者多个线程之间的切换不会导致该接口的执行结果存在二义性, 也就是说我们不用考虑同步的问题,那就是线程安全的。
阅读全文
0 0
- 单例模式singleton —— II
- 单例模式——Singleton
- 单例模式——Singleton
- 单例模式——Singleton
- Singleton——单例模式
- 设计模式——单例Singleton
- 设计模式——单例Singleton
- 单例设计模式——singleton
- 单例模式——Singleton Pattern
- 单例模式singleton —— I
- Java设计模式—singleton 单例
- Objective —C 单例模式 Singleton
- Singleton单例模式——类模板单例
- 设计模式————单例模式Singleton
- JAVA设计模式——单例(Singleton)模式
- 设计模式——单例模式【Singleton Pattern】
- 设计模式——单例(Singleton)模式
- java设计模式——单例模式(Singleton)
- 天南地北话“事务”
- 最长公共连续子串和最长连续公共子序列
- 数据库基本概念
- (转)写一个网页进度loading
- [日常练习]算
- 单例模式singleton —— II
- Convert BST to Greater Tree
- Android APP架构思考
- 805A Fake NP
- 选择排序(C语言实现)
- Struts2传值的3种方式
- 0x01 【Linux入门学习之】vi/vim编辑器必知必会
- Cache缺失率的计算
- Java技术是什么