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

一:恶汉模式,类加载的时候就已经把对象初始化好了。(为了防止在其他类中使用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) {// 1
			singleton2 = 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) {// 1
			singleton3 = 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){//1
			synchronized(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){//1
			synchronized(Singleton5.class){
				if(singleton5==null){//2
					singleton5 =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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值