单例模式简单理解

    因为原来不太注重基础,对单例模式的理解和使用比较浅,这些天正好需要面试,就重新学习了一下,下面进入正题。单例模式指一个程序中的某个类只有一个实例,一些管理器和控制器被设计成单例模式。如果程序有一些配置文件,在程序运行时整个程序只需要一个类的实例来读取这些配置,供其他方法的调用。

    优点:不用重复创建,节约资源,节约内存空间,提升系统性能。

    缺点:使用时适当选择,不适合经常改变的对象。

    单例模式的几种写法。

1.饿汉模式

public class Singleton{
	private static Singleton instance = new Singleton();
	
	private Singleton(){}

	public static Singleton getInstance(){
		return instance;
	}
}

    饿汉模式是在类被加载时就创建了实例,它的好处是在类加载时就创建了实例,不会出现多个线程创建多个实例的情况,避免了线程同步的问题;坏处是此单例如果需要较大的内存,就造成了内存浪费,所以这就需要延迟加载(在需要时进行加载)。

2.懒汉模式

public class Singleton{
	private static Singleton instance = null;

	private Singleton(){}

	public static Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}

		return instance;
	}
}

    懒汉模式是在被需要时才进行加载,这样做会节约内存开销,但是也会存在线程安全的问题,当多个线程调用getIntance()方法时,会创建多个实例,这时,我们需要给方法加锁来解决线程同步问题。

public class Singleton{
	private static Singleton instance = null;

	private Singleton(){}

	public static synchronized Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}

		return instance;
	}
}

    虽然加锁解决了线程同步的问题,但是synchronized会消耗很多资源,性能不佳。这就产生了双重校验锁。

3.双重校验锁

public class Singleton{
	private static Singleton instance = null;

	private Singleton(){}

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


		return instance;
	}
}

    在加锁语句块外面还加了一个实例判断,有利于在实例创建后,直接进行判断,不用再去加锁语句块里判断,提升了性能。说明下应用场景:当线程A调用getInstance()方法,此时instance为null,进而进入到加锁语句块,此时,线程B也调用getInstance()方法,因为A刚进入加锁语句块,instance实例还未创建,所以语句块外的判断为true,等待进入加锁语句块,处于阻塞状态,当线程A创建完成后,释放锁,线程B获取锁,但是此时instance已经被创建,所以线程B不会再创建实例。

    这还会有个问题,因为Java中JVM指令重排优化的存在。指令重排优化指:在不改变指令语义的情况下,调整指令执行顺序来提高系统运行速度。这就存在Singleton类初始化和给instance分配内存地址顺序不确定的问题。出现场景:当一个线程创建单例对象时,在构造方法执行之前,就对instance进行了内存分配,此时另一个线程同样创建单例对象,此时对象状态不对,会出现程序错误。

    jdk1.5后,出现了volatile关键字,意思为:禁止指令重排

public class Singleton{
	private static volatile Singleton instance = null;

	private Singleton(){}

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


		return instance;
	}
}

4.静态内部类

public class Singleton {

    private static class SingletonHolder{
        private static Singleton instance = new Singleton();
    }

    private Singleton(){}

    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
}

    利用类加载机制来保证只有一个实例instance,并保证线程同步安全,同饿汉模式,同时用内部类来实现,表明只在内部类被调用时才会加载,又实现了延迟加载,同懒汉模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值