Java 多线程下的单例模式的设计

来源:互联网 发布:外网端口查询 编辑:程序博客网 时间:2024/06/04 11:19
单例模式我们在代码设计中会经常用到。但是在多线程情况下,如果没有贴别处理,往往结果并非我们所期望的。一般单例模式的代码如下:
public class Singleton{    private static Singleton sInstance = null;    private Singleton(){        //init    }    public static Singleton getInstance(){        if ( sInstance == null){            sInstance = new Singleton();        }         return sInstance;    }}

这块代码在单线程中时没有问题的,但是假设有两个线程同时调用getInstance()方法,两个线程进入if后发现说Instance是null,都会去实例化一个Singleton对象,这样的话就不是单例了。下面就详细分析一下几种解决方案。

方案一:加载时就实例化。

private static Singleton sInstance = new Singleton();
这种方法违背了java的lazy-load原则,即使用时才加载,本例中sInstance的所在类和sInstance的类型一样,就不存在这个问题了,但是,假若Singleton的构造方法中有比较耗时的造作时,就会大大加大了类加载的时间。

方案二:synchronized关键字,代码修改如下:

public class Singleton{    private static Singleton sInstance;    private Singleton(){        //init    }    public static synchronized getInstance(){        if (sInstance == null){            sInstance = new Singleton();        }        return sInstance;    }}

这种写法的确能够保证同步,但是每次在获取实例的时候,都需要获取同步锁,这就比较耗时,效率不高。于是,就有了方案三和方案四。

方案三:减少获取同步锁的次数

    public static getInstance(){        if (sInstance == null){            syncInit();        }        return sInstance;    }    private void synchronized syncInit(){        if (sInstance == null){            sInstance = new Singleton();        }    }
这种方案和方案二相比,只在单例没有被实例化的时候才会去竞争同步锁,大大的降低了时间的消耗。

方案四:利用JVM在加载class的时候是同步的原理

public class Singleton{    private static class SingletonContainer{        static Singleton sInstance = new Singleton();       }      private Singleton(){//init      }      public static getInstance(){               return SingletonContainer.sInstance;       }}


JVM在加载class的时候有一种lazy-load机制,即在需要的时候才去加载,所以当我们第一次调用getInstance方法的时候,JVM才会去加载SigletonContainer类,并且JVM有同步机制保证SigletonContaner类只被加载一次,这样就保证了sIntance只被实例化一次。

	
				
		
原创粉丝点击