实现Singleton 模式—六种实现方式

版权声明:本文为作者的原创文章,未经允许不得转载。 https://blog.csdn.net/lele1658676840/article/details/82416164

1. 饿汉式(线程安全)

public static class Singleton{
	private final static Singleton INSTANCE = new Singleton();
	private Singleton{
	
	}
	public static Singleton getInstance(){
		return INSTANCE;
	}		
}

饿汉模式在类被初始化时就已经在内存中创建了对象,以空间换时间,故不存在线程安全问题。

2. 懒汉式(线程不安全)

public static class Singleton{
	private static Singleton INSTANCE = null;
	private Singleton{

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

懒汉模式在方法被调用后才创建对象,以时间换空间,在多线程环境下存在风险。

3. 懒汉式(线程安全,多线程下效率不高)

public static class Singleton{
	private static Singleton INSTANCE = null;
	private Singleton{

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

4. 懒汉式(线程安全)

public static class Singleton{
	private static Singleton INSTANCE = null;
	static{
		INSTANCE = new Singleton();
	}
	private Singleton{
	
	}
	public static Singleton getInstance(){
		return INSTANCE;
	}
}

5. 双重锁懒汉式(线程安全)

public static class Singleton{
	private volatile static Singleton INSTANCE = null;
	private Singleton{
	
	}
	public static Singleton getInstance(){
		if(INSTANCE == null){
			synchnronized(Singleton.class){
				if(INSTANCE == null){
					INSTANCE = new Singleton();
				}
			}
		}
		return INSTANCE;
	}
}

DCL模式的优点就是,只有在对象需要被使用时才创建,第一次判断 INSTANCE == null为了避免非必要加锁,当第一次加载时才对实例进行加锁再实例化。这样既可以节约内存空间,又可以保证线程安全。但是,由于jvm存在乱序执行功能,DCL也会出现线程不安全的情况。具体分析如下:
INSTANCE = new SingleTon();
这个步骤,其实在jvm里面的执行分为三步:

1.在堆内存开辟内存空间。
2.在堆内存中实例化SingleTon里面的各个参数。
3.把对象指向堆内存空间。

由于jvm存在乱序执行功能,所以可能在2还没执行时就先执行了3,如果此时再被切换到该线程上,由于执行了3,INSTANCE 已经非空了,会被直接拿出来用,这样的话,就会出现异常。这个就是著名的DCL失效问题

不过在JDK1.5之后,官方也发现了这个问题,故而具体化了volatile,即在JDK1.6及以后,只要定义为private volatile static SingleTon INSTANCE = null;就可解决DCL失效问题。volatile确保INSTANCE每次均在主内存中读取,这样虽然会牺牲一点效率,但也无伤大雅。

6. 静态内部类(线程安全,推荐)

public static class Singleton{
    private final static class SingletonHolder{
        private final static Singleton INSTANCE = new Singleton();
    }
    private Singleton{

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

猜你喜欢

转载自blog.csdn.net/lele1658676840/article/details/82416164