单例模式

单例模式

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

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

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;

posted @ 2020-05-08 20:19  木灬匕禾页  阅读(81)  评论(0)    收藏  举报