(一)单例模式

设计模式:是一套被反复使用,多数人知晓,经过分目编类的,代码设计经验的总结。

目的:使用设计模式是为了可重用代码,让代码更容易被他人所理解,保证代码的可靠性

单例模式:一个类只有一个实例,并提供全局访问点

单例模式两大类基础实现:

    (1)饿汉模式:实例在类加载的时候就被创建,线程安全,性能比较低,创建慢但是加载快,加载过早的话可能会浪费资源

	private static Singleton uniqueInstance = new Singleton();
	
	private Singleton(){}
	
	public static Singleton getUniqueInstance(){
		return uniqueInstance;
	}

    (2)懒汉模式:实例在第一次被使用时创建,非线程安全

	private static Singleton uniqueInstance;
	
	private Singleton(){}
	
	public static Singleton getInstance(){
		if(uniqueInstance == null){
			uniqueInstance = new Singleton();
		}
		return uniqueInstance;
	}

单例模式当中的线程安全:

    上文中的懒汉式实现方法,在单线程的时候不会有任何问题,但是在多线程的情况下,当两个线程同时执行到if语句的时候,如果此时都判断uniqueInstance==null(第一个线程还未创建完实例,第二个线程就进入判断语句),那么两个线程会各自创建一个实例,就破坏了单例模式的实例唯一性。

如何解决线程安全问题:

    首先我们想到的会是加Synchronized关键字,加上同步锁实现线程安全,这样如果存在两个线程同时进入方法,那么只有一个线程可能获得同步锁,而另一个线程则需要等待,直到第一个线程释放锁(即完成现成的创建或者返回),第二个线程才有机会获得锁,这样就避免了因为第一个线程未执行完毕而第二个线程判断uniqueInstance==null,从而创建两个实例的情况,但是这种方法很显然不够高效,因为只有在创建线程时才会出现线程安全性问题,如果实例已经创建只是单纯的返回,则不需要加锁。具体实现如下:

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

    为了更加高效的实现线程安全,可以使用双重检查(Double-Check),即上一种方法的一种优化

	public static Singleton getInstance(){
		if(uniqueInstance == null){
			synchronized(Singleton.class){
				if (uniqueInstance == null) {
					uniqueInstance = new Singleton();
				}
			}
		}
		return uniqueInstance;
	}

  为什么要用两重检查而不是一重检查

             第一个if是为了提高效率,只有当uniqueInstance==null时才会加锁,大大减少了进入锁的概率

             第二个if则是为了防止重复创建实例,

            如果只有第一个锁的话,还是没有办法防止重复创建实例

上面实现双重检查方法所隐藏的问题:

    因为计算机为了提高效率,会进行一些优化,比如java内存模型会进行指令重排序

    在上面的代码中 uniqueInstance = new Singleton();并非原子操作,JVM会进行三步操作:

    1)给Singleton分配内存

    2)调用Singleton的构造函数来初始化成员变量,形成实例

    3)将Singleton对象指向分配的内存空间

    但是由于存在指令重排序问题,2,3步有可能颠倒执行,如果这样的话,当第一个线程执行到3但是未执行2时,第二个线程进来,判断uniqueInstance!=null,直接返回Instance,但是这是线程1对Instance的操作还未完成,所以会产生错误

    为了解决这样的错误,给UniqueInstance添加一个Volatile关键字,volatile具有禁止指令重排序问题

  private volatile static Singleton uniqueInstance;	

其他方法实现单例模式:

    1)静态内部类利用类加载机制保证创建一个实例线程安全,并且没有性能损耗

	public Singleton() {
		// TODO Auto-generated constructor stub
	}
	private static class sigletonL{
		private static final Singleton2 uniqueInstance = new Singleton2();
	}
	
	public static Singleton2 getUniqueInstance(){
		return sigletonL.uniqueInstance;
	}

    2)枚举 简单,高效,安全

	public enum Singleton{
		UNIQUEINSTANCE;
		public void func(){
			
		}
	}

单例模式的优点:

    1)在内存中只有一个对象,节约资源

   2) 避免繁琐的创建销毁对象,可以提高性能

    3)避免对共享资源的多重占用

    4)可以全局访问

单例模式的缺点:

    1)扩展困难

    2)导致程序内存泄漏的问题



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值