单例模式保证了程序中有且只有一个实例但可以在全局中被访问到。
所以你在项目开发中希望某各类的对象只能被实例化一次而且该对象频繁被访问,单例模式应该是最好的解决方案。
那么单例模式有什么优点呢?
a) 只有一个实例,避免了对象的重复创建,减少了内存的开销
b) 避免了对资源的重复访问和操作
单例模式常用的几种写法:
1)懒汉式
public class Singleton {
private static Singleton instance=null;
private Singleton() {}
public static Singleton getInstance() {
if(instance==null) {instance=new Singleton();}
return instance;
}
}
优点:延迟加载(需要的时候才去加载)
缺点: 线程不安全,在多线程中很容易出现不同步的情况,比如频繁执行数据库操作的时候。
2)加同步锁方式
public static synchronized Singleton getInstance() {
if(instance ==null) { instance =new Singleton(); } return instance;
}
优点:解决了线程不安全的问题
缺点:每次调用都要判断同步锁,导致效率较低
3)双重检验锁方式
虽然上面这种写法是可以正确运行的,但是其效率较下,还是无法实际应用。因为每次调用getSingleton()方法,都必须在synchronized这里进行排队,而真正遇到需要new的情况是非常少的,所以就有了双重检验锁的方式
public static synchronized Singleton getInstance(){
if(instance == null){ synchronized(Object){ if(instance == null){ instance = new Singleton(); } } }
}
在getSingleton()方法中,进行两次instance ==null的检查。正如上面所说在单例中new的情况非常少,绝大多数都是可以并行的读操作。因此在加锁前多进行一次null检查就可以减少绝大多数的加锁操作,从而极大地提升了并发量,进而提升了性能
优点:在并发量不高、安全性不高的情况下可以很好的运行
缺点:在jdk1.5版本前,双重检查锁形式的单例模式是无法保证线程安全的。
4)静态内部类方式
将Singleton实例置于一个静态内部类中,这样就可以避免了静态实例在Singleton类加载的时候就创建对象,并且由于静态内部类只会被加载一次,所以这种写法也是线程安全的。
public class Singleton {
private static class Holder {
private static Singleton singleton = new Singleton();
}
private Singleton(){}
public static Singleton getInstance(){ return Holder.singleton; }
}
优点:延迟加载、线程安全、减少内存开销