单例模式分为三种:
第一种:饿汉模式
//饿汉模式,很饿很着急,所以类加载时即创建实例对象
public class SingletonHungry{
private static SingletonHungry singleton = new SingletonHungry();
private SingletonHungry(){} public static SingletonHungry getInstance(){ return singleton; } }
优点:由于是static属性,在类加载过程中就会被创建,可以保证全局唯一,因此它是现成安全的。获取对像只需要调用getInstance方法即可。
缺点:无论你用不用得到,它都会被加载进来,如果单例很多,而且单例的数据量很大,又用不到的话,很浪费系统资源。
第二种:懒汉模式
//懒汉模式 需要时才加载,存在线程安全问题,但是可以通过双重判断和synchornized关键字来解决
public class SingletonLazy {
private static SingletonLazy singleton;
private SingletonLazy(){}
public static SingletonLazy getInstance(){
if(singleton == null){
synchronized(SingletonLazy.class){
if(singleton == null)
singleton = new SingletonLazy();
}
}
return singleton;
}
}
优缺点:懒汉模式可以实现用时加载,但是它有县城安全的问题,加入synchronized关键字可以解决,但是锁粒度要控制好,避免锁竞争造成的资源消耗。
如上面例子代码,经过低粒度锁和双重判断,在首次加载时会使用到synchronized即可,一旦对象加载完成,就不会再进入锁竞争的代码块。性能上也得到了极大提升,线程安全也得到了保障。
第三种:静态内部类模式
class SingletonStaticInnerClass {
private static class InnerSingleton {
private static SingletonStaticInnerClass single = new SingletonStaticInnerClass();
}
private SingletonStaticInnerClass() {
}
private static SingletonStaticInnerClass getInstance() {
return InnerSingleton.single;
}
}
静态内部类利用JDK的特性,内部类(不论是静态内部类还是非静态内部类)都是在第一次使用时才会被加载。这样可以保证单例对象只有在第一次被使用的时候初始化一次,并且不需要枷锁,性能大大提高,并且保证了线程安全。