1.2懒汉模式及其问题、静态内部类实现单例模式

懒汉模式代码

package Singleton;


public class LazySingleton {
	private static LazySingleton lazySingleton=null;
	private LazySingleton() {
		
	}
	public static LazySingleton getInstance() {
		if(lazySingleton==null)
			lazySingleton=new LazySingleton();
		return lazySingleton;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

懒汉模式最主要得就是会在多线程中重复创建 对象实例,若线程较多则会导致内存使用过大,甚至导致程序崩溃。测试代码如下

Test代码:

package Singleton;

public class Test {

	public static void main(String[] args) {
		Thread t1=new Thread(new T(),"Thread_1");
		Thread t2=new Thread(new T(),"Thread_2");
		t1.start();
		t2.start();
		// TODO Auto-generated method stub

	}

}

实习Runnable接口代码如下

package Singleton;


public class T implements Runnable {
	public void run() {
		System.out.println(Thread.currentThread().getName()+" "+LazySingleton.getInstance());
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

虽然运行之后,结果输出得 实例 是同一个实例,但是这个结果是不确定得,也有可能会输出多个实例。即便输出同一个对象实例,但是中间会多次创建对象实例,后一个覆盖前一个对象,会造成内存资源的消耗,所以懒汉模式是一种不可取的方式。

解决方法:利用synchronized加到方法上,锁住这个类

package Singleton;


public class LazySingleton {
	private static LazySingleton lazySingleton=null;
	private LazySingleton() {
		
	}
	public synchronized static LazySingleton getInstance() {
		if(lazySingleton==null)
			lazySingleton=new LazySingleton();
		return lazySingleton;
	}
	//下面这个形式和上面的是一样的,都是将这个类加了锁,同一时间只允许一个线程访问这个类
//	public  static LazySingleton getInstance() {
//		synchronized(LazySingleton.class) {
//			if(lazySingleton==null)
//				lazySingleton=new LazySingleton();
//		}
//		return lazySingleton;
//	}


	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

注意:多线程debug,要切换断点设置为Thread模式下,不能是All模式下,Thread模式下,每个线程的断点都可以真的起到作用,但是All模式下,只能断到主线程的断点。

直接将synchronized加在方法上,开销较大,因此我们使用DoubleCheck方式,代码如下

package Singleton;

public class LazyDoubleCheckSingleton {
	private static LazyDoubleCheckSingleton lazyDoubleCheckSingleton=null;
	private LazyDoubleCheckSingleton() {
		
	}
	public static LazyDoubleCheckSingleton getInstance() {
		if(lazyDoubleCheckSingleton==null) {
			synchronized (LazyDoubleCheckSingleton.class) {
				if(lazyDoubleCheckSingleton==null)
					lazyDoubleCheckSingleton=new LazyDoubleCheckSingleton();
			}
		}
		return lazyDoubleCheckSingleton;
	}
	

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

有了双重检查后,当进入方法,判断lazyDoubleCheckSingleton是否为null,当不为null时,直接返回lazyDoubleCheckSingleton即可,就省去了锁开销。但是仍有隐患,如下图

步骤2 3在单线程中允许重排序,所以出现上图问题。

改进措施(解决重排序):将成员变量lazyDoubleCheckSingleton加上volatile修饰符,使其写操作具有可见性。(volatile的汇编语言多了一些代码,就是在写操作后使这个内存对象的缓存无效,当再需要用时,需要再从系统内存中读到处理器的缓存里,即可见性)

private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton=null;

基于类初始化的延迟加载:静态内部类

原理:外部类加载时,不一定加载内部类,内部类不加载则不会去初始化instance,故而不占用内存,只有当getInstance()方法第一次被调用时,才会去初始化instance,延迟了单例的实例化,也使得线程安全,代码如下

package Singleton;

public class StaticInnerClassSingleton {
	private StaticInnerClassSingleton() {
		
	}
	private static class InnerClss{
		private static StaticInnerClassSingleton scs=new StaticInnerClassSingleton();
	}
	public StaticInnerClassSingleton getInstance() {
		return InnerClss.scs;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

存在隐患:静态内部类无法传参

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值