当前位置:   article > 正文

单例模式几种使用方法_单例类调用

单例类调用

单例模式特点:

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。

1.饿汉式单例

  1. public class HungrySingleton {
  2. public static HungrySingleton instance = new HungrySingleton();
  3. /**
  4. *默认创建一个私有构造类
  5. */
  6. private void HungrySingleton(){}
  7. /**
  8. *静态工厂方法
  9. */
  10. public static HungrySingleton getInstance() {
  11. return instance;
  12. }
  13. }

饿汉式是典型的空间换时间,在类初始化加载的时候就创建了对象,在调用的时候节省了创建的时间。

2.懒汉式单例

  1. public class LazySingleton {
  2. public static LazySingleton instance = null;
  3. /**
  4. *默认创建一个私有构造类
  5. */
  6. private void LazySingleton(){}
  7. /**
  8. *静态工厂方法
  9. */
  10. public static synchronized LazySingleton getInstance() {
  11. if (instance == null) {
  12. instance = = new LazySingleton();
  13. }
  14. return instance;
  15. }
  16. }

1.懒汉式特点,在类加载是不创建对象,调用getInstance()方法时如果instance为null才去创建对象。 2.而且在方法名前加了synchronized锁,是线程安全的,但是有一个弊端每次都要判断是否为空,比较慢(时间换空间)

3.双重检查加锁

  1. public class DoubleCheckSingleton {
  2. public volatile static DoubleCheckSingleton instance = null;
  3. /**
  4. *默认创建一个私有构造类
  5. */
  6. private void DoubleCheckSingleton(){}
  7. /**
  8. *静态工厂方法
  9. */
  10. public static LazySingleton getInstance() {
  11. if (instance == null) {
  12. //同步代码块
  13. synchronized (DoubleCheckSingleton.class) {
  14. if (instance == null) {
  15. instance = = new LazySingleton();
  16. }
  17. }
  18. }
  19. return instance;
  20. }
  21. }

双重检查主要是先不在方法中加锁(防止速度变慢),先判断instance是否为空,然后再使用同步代码块,再次判断instance是否为空,为空的话创建对象。

优势在于不用每次都同步,只有在instance为null的时候才创建对象,(优于懒汉式

“双重检查加锁”机制的实现会使用关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。

:由于volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高。因此一般建议,没有特别的需要,不要使用。也就是说,虽然可以使用“双重检查加锁”机制来实现线程安全的单例,但并不建议大量采用,可以根据情况来选用(volatile又会影响速度,所有懒汉式和双重加锁都有缺陷,建议尽量减少使用)

4.Lazy initialization holder class模式

在多线程开发中,为了解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制。但是在某些情况中,JVM已经隐含地为您执行了同步,这些情况下就不用自己再来进行同步控制了。这些情况包括:

1.由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时

2.访问final字段时

3.在创建线程之前创建对象时

4.线程可以看见它将要处理的对象时

:类加载时会先加载static变量和static代码块(static{})

解决方案的思路

要想很简单地实现线程安全,可以采用静态初始化器的方式,它可以由JVM来保证线程的安全性。比如前面的饿汉式实现方式。但是这样一来,不是会浪费一定的空间吗?因为这种实现方式,会在类装载的时候就初始化对象,不管你需不需要。

如果现在有一种方法能够让类装载的时候不去初始化对象,那不就解决问题了?一种可行的方式就是采用类级内部类,在这个类级内部类里面去创建对象实例。这样一来,只要不使用到这个类级内部类,那就不会创建对象实例,从而同时实现延迟加载和线程安全。

  1. public class Singleton {
  2. private void Singleton(){}
  3. /**
  4. * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
  5. * 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
  6. */
  7. private static class SingletonHolder{
  8. /**
  9. * 静态初始化器,由JVM来保证线程安全
  10. */
  11. private static Singleton instance = new Singleton();
  12. }
  13. public static Singleton getInstance(){
  14. return SingletonHolder.instance;
  15. }
  16. }

当getInstance方法第一次被调用的时候,它第一次读取SingletonHolder.instance,导致SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。这个模式的优势在于,getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。

参考资料:http://www.cnblogs.com/java-my-life/archive/2012/03/31/2425631.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/157649?site
推荐阅读