首页 > 其他 > 详细

单例模式

时间:2020-05-08 21:11:38      阅读:41      评论:0      收藏:0      [点我收藏+]

单例模式

单例模式,就是一个类只能实例化一个对象;

在多线程下,一个常见的模板是这样的

package singleton;
public class PrintSpoolerSingleton
{
   private volatile static PrintSpoolerSingleton instance = null;
   private PrintSpoolerSingleton()
   {  
   }
   
   public static PrintSpoolerSingleton getInstance() throws 
   {
      if(instance == null){
         System.out.println("创建打印池!");
         synchronized (PrintSpoolerSingleton.class){
            if(instance == null){
               instance = new PrintSpoolerSingleton();
            }
         }
      }
      return instance;
   }
}

注意的点

构造方法私有---这样保证外部无法通过new创造对象,保证单一;

实例化对象private且static---提供一个静态getInstance来获取单例对象,而静态方法里面需要静态对象;

饿汉式和懒汉式---上面的代码是懒汉式,饿汉式则是在初始化时就实例化好

private static PrintSpoolerSingleton instance = new PrintSpoolerSingleton();

为什么要双重判断?

你们可能想这样写

public synchronized static PrintSpoolerSingleton getInstance()
   {
      if(instance == null){
         instance = new PrintSpoolerSingleton();
      }
      return instance;
   }

但是这样写在并发下效率比较低;

因为每次请求都需要锁,但是我们其实只是“读”而已;

“读”的过程并不需要同步,只有在new的时候才需要,所以应该是在判断为null是再加锁;

改成下面这种

public static PrintSpoolerSingleton getInstance() throws PrintSpoolerException
{
    if(instance == null){
        synchronized(PrintSpoolerSingleton.class){
            instance = new PrintSpoolerSingleton();
        }
    }
    return instance;
}

然而,这种也有问题;

如果有两个线程同时判断到instance为null,那它们都会进到里面,最后出现多次实例化;

那么就写成这样

public static PrintSpoolerSingleton getInstance() throws 
{
    if(instance == null){
        synchronized (PrintSpoolerSingleton.class){
            if(instance == null){
                instance = new PrintSpoolerSingleton();
            }
        }
    }
    return instance;
}

用了双重锁之后,其实还不够完善,这里涉及到JVM指定优化方面的问题;

问题出在下面这句

instance = new PrintSpoolerSingleton();

虚拟机做了三个步骤:

1.给instance分配内存

2.调用构造方法完成初始化

3.使instance对象的引用指向分配的内存空间

完成第3步时instance就不为null了,而JVM优化时使得指令可能不会按照1-2-3的顺序执行,这样就可能造成还没有真正的实例化成功,一个线程判断发现不为null,然后就返回instance了;

所以你会看到对象变量上面还有一个关键词volatile,它能防止指令重排

private volatile static PrintSpoolerSingleton instance = null;

单例模式

原文:https://www.cnblogs.com/Jayyi/p/12852832.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!