1. 全局变量的缺点:数据库
必须在程序一开始就建立好对象,若是程序在此次的执行过程当中又一直没用到它,就很是耗费资源。缓存
2. 经典的单例模式实现:安全
public class Singleton { //用一个静态变量来记录Singleton类的惟一实例 private static Singleton uniqueInstance; private Singleton() {} //注意这个方法也是静态的 public static Singleton getInstance() { if(uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } }
单例常被用来管理共享的资源,例如数据库链接、线程池、缓存、注册表。多线程
单例模式确保一个类只有一个实例,并提供一个全局访问点。性能
这个模式的问题:在多线程时,并不能保证这个类只被实例化一次。优化
3. 处理多线程:spa
经过增长synchronized关键字到getInstance()方法中,迫使每一个线程在进入方法以前,要先等别的线程离开该方法。也就是说,不会有两个线程能够同时进入这个方法。线程
这种方法存在的问题:只有第一次执行此方法时,才真正须要同步。换句话说,一旦设置好uniqueInstance变量,就再也不须要同步这个方法了。以后每次调用这个方法,同步都是一种浪费。code
4.改善多线程对象
4.1 若是getInstance()的性能对应用程序不是很关键,就不用优化了
4.2 使用急切建立实例,而不用延迟实例化的作法
public class Singleton { private static Singleton uniqueInstance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return uniqueInstance; } }
标红的语句在静态初始化器(static initializer)中建立单例,这保证了线程安全。
利用这个作法,JVM在加载这个类时立刻建立此惟一的单件实例。JVM保证任何线程访问uniqueInstance静态变量以前,必定先建立些实例。
4.3 用“双重检查加锁”,在getInstance()中减小使用同步
首先检查实例是否已经建立,若是还没有建立,才进行同步。这样一来,只有第一次会同步,这正是咱们想要的。
public class Singleton { private volatile static Singleton uniqueInstance; private Singleton() {} public static Singleton getInstance() { if(uniqueInstance == null) {//(1)
//只有第一次才完全执行这里的代码 synchronized() { //再检查一次 if(uniqueInstance == null) uniqueInstance = new Singleton(); } } return uniqueInstance; } }
在最开始若是有一、二、3个线程走到了(1)处,假设1进入了同步块,二、3等待。1实例化后,2进入同步块,发现uniqueInstance已经不为空,跳出同步块。接着3进入,又跳出同步块。
volatile关键字确保:当uniqueInstance变量被初始化成Singleton实例时,多个线程正确地uniqueInstance变量。若是性能是你关心的重点,那么这个作法能够帮你大大地减小getInstance()的时间耗费。