【博学谷学习记录】超强总结,用心分享 | 第12周:java实现单例的方式

这周复习了一些基础的内容,其中有一条就是java如何实现单例的过程。

最基础的就是饿汉式。所谓饿汉式,就是在类加载时,就已经创建了单例,而不是在get方法执行时才创建。

public class Singleton1 implements Serializable {

	private Singleton1() {
			System.out.println(“private Singleton1()”);
	}
	
	private static final Singleton1 INSTANCE = new Singleton1(); 
	
	public static Singleton1 getInstance() {
		return INSTANCE;
	}
	
	public static void otherMethod() {
		System.out.println(“otherMethod()”);
	}

}

这种方法的问题在于,反射或者反序列化都可以破坏单例。

为了防止反射的破坏,可以在构造方法里添加null的判断。

public class Singleton1 implements Serializable {

	private Singleton1() {
        if(INSTANCE != null) {
            throw new RuntimeException("单例不能重复");
        }
		System.out.println(“private Singleton1()”);
	}
	
	private static final Singleton1 INSTANCE = new Singleton1(); 

	public static Singleton1 getInstance() {
		return INSTANCE;
	}
	
	public static void otherMethod() {
		System.out.println(“otherMethod()”);
	}

}

如果想要反序列化,就需要加上readResolve() 方法

public class Singleton1 implements Serializable {

	private Singleton1() {
        if(INSTANCE != null) {
            throw new RuntimeException("单例不能重复");
        }
		System.out.println(“private Singleton1()”);
	}
	
	private static final Singleton1 INSTANCE = new Singleton1(); 

	public static Singleton1 getInstance() {
		return INSTANCE;
	}
	
	public static void otherMethod() {
		System.out.println(“otherMethod()”);
	}

    public Object readResolve() {
        return INSTANCE;
    }

}

第二种方法是枚举饿汉式

public enum Singleton2 {
	
	INSTANCE;
	
	private Singleton2(){
		System.out.println(“private Singleton2()”);
	}
	
	@Override
	public String toString() {
		return getClass().getName() + “@“ + Integer.toHexString(hashCode());
	}
	
	public static Singleton2 getInstance(){
		return INSTANCE;
	}
	
	public static void otherMethod(){
		System.out.println(“otherMethod()”);
	}
	
}

这种方法天然能够屏蔽反射破坏和反序列化破坏。

第三种,懒汉式。

public class Singleton3 implements Serializable {

	private Singleton3() {
		System.out.println(“private Singleton3()”);
	}
	
	private static final Singleton3 INSTANCE= null;
	 
	public static Singleton3 getInstance() {
		if (INSTANCE == null) {
			INSTANCE = new Singleton3();
		}
		return INSTANCE;
	}
	
	public static void otherMethod() {
		System.out.println(“otherMethod”);
	}
}

这种如果是单线程则没有问题,但如果是多线程,可能两个线程同时进入到getInstance的if语句当中,导致重复创建单例。

为了解决这个问题,可以添加一个synchronized的锁,但与此同时出现的问题就是,只有在创建实例时需要锁,后续则会成为运行的负担。

第四种,双检懒汉式

public class Singleton4 implements Serializable {

	private Singleton4() {
		System.out.println(“private Singleton()”);
	}
	
	private static volatile Singleton4 INSTANCE = null;
	
	public static Singleton4 getInstance() {
	
		if (INSTANCE == null){
			synchronized (Singleton4.class) {
				if (INSTANCE == null) {
					INSTANCE = new Singleton4();
				}
			}
		}
		return INSTANCE;
	}
	
	public static void otherMethod() {
		System.out.println(“otherMethod()”);
	}

}

这种方式解决了普通懒汉式的问题,这个过程中单例一定要添加volatile的限制,保证单例在构造之后才会赋值,否则也可能出现空对象的情况。

5.内部类懒汉式

由于静态代码不存在重复创建的问题,所以把创建实例的功能放到内部的静态代码当中,这样就避免了双检的缺点了。

public class Singleton5 implements Serializable {

	private Singleton5() {
		System.out.println(“private Singleton5()”);
	}
	
	private static class Holder {
		static Singleton5 INSTANCE = new Singleton();
	}
	
	public static Singleton5 getInstance() {
		return Holder.INSTANCE;
	}
	
	public static void otherMethod() {
		System.out.println(“otherMethod()”);
	}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值