java设计模式之单列模式(懒汉,恶汉,double-check- lock)

来源:互联网 发布:淘宝产品视频 编辑:程序博客网 时间:2024/05/16 07:51

一:恶汉模式,类加载的时候就已经把对象初始化好了。(为了防止在其他类中使用new 操作符创建对象,要使用一个private 标记的 构造方法)

package single;public class Singleton1 {public static final Singleton1 singleton=new Singleton1();private Singleton1() {}public static Singleton1 getInstance(){return singleton;}}

二:懒汉模式(懒加载)

package single;public class Singleton2 {public static Singleton2 singleton2 = null;private Singleton2() {// TODO Auto-generated constructor stub}public static Singleton2 getInstance() {if (singleton2 == null) {// 1singleton2 = new Singleton2();//2}return singleton2;}}


这种懒汉模式会造成线程安全问题,比如假如有两个线程A,B,都执行到上面的第二步,那么就生成了两个对象,后执行第二步生成的对象替换掉了

先执行第二步生成的那个对象。怎么办呢,加锁啊。。

三:加上同步锁

package single;public class Singleton3 {public static Singleton3 singleton3 = null;private Singleton3() {// TODO Auto-generated constructor stub}public synchronized static Singleton3 getInstance() {if (singleton3 == null) {// 1singleton3 = new Singleton3();// 2}return singleton3;}}


上面到不会造成线程安全问题了。但是效率低啊,假设有10个线程,第一个线程执行方法的时候,后面的都得排队。。怎么办?换个方式加锁

四:同步锁2

package single;public class Singleton4 {public static  Singleton4 singleton4=null;private Singleton4() {// TODO Auto-generated constructor stub}public static Singleton4 getInstance(){if(singleton4==null){//1synchronized(Singleton4.class){singleton4 =new Singleton4();//2}}return singleton4;}}

这个和三的列子差不多,虽然好点,但是仍然会造成线程并发问题,假如有10个线程执行了第一步,进行了null check,然后就会创建10个对象,怎么办呢,double-check- lock .

五:同步锁3

package single;public class Singleton5 {public static  Singleton5 singleton5=null;private Singleton5() {// TODO Auto-generated constructor stub}public static Singleton5 getInstance(){if(singleton5==null){//1synchronized(Singleton5.class){if(singleton5==null){//2singleton5 =new Singleton5();//3}}}return singleton5;}}

怎么样呢?似乎是完美无缺啊。但是,仍然不行,因为第三步 singleton5=new Singleton5()并不是原子操作,他事实上分三步 (1),分配 memory,(2)把对象的引用 指派给memory (3) 初始化memory,假如有一个线程,执行完了同步块,但是却卡在了(3)步,那么其他线程拿到的就是一个没有被初始化完成的对象。囧。。。。。不过别担心,我们仍然有办法。

五:变量singleton5前加volatile 关键字(volatile关键字保证了可见性,但不保证原子性,可见性的意思就是,一个线程对一个资源的修改,另一个线程会得到通知。可以参考这篇blog)不过据说有些jvm并没有实现volatile规范。。。。。)

六:内部类方式。

如果想保证线程安全,不想要lazy加载的话,第一种最合适,但如果想要线程安全,又先要lazy加载的话,我们还可以使用内部类的方式。

package single;public class Singleton6 {private static class InnerClass {public static final Singleton6 singleton6 = new Singleton6();}public static Singleton6 getInstance() {return InnerClass.singleton6;}}

内部类在第一次被调用的时候才被初始化

七:最高端大气上档次的是enum枚举类的方式

package single;public enum Singleton7 {singleton7;}

每一个枚举类的常量都是这个枚举类的一个实列。。。。。

1 0