让星星⭐月亮告诉你,(饿汉式3种【直接实例化\枚举\静态代码块】+懒汉式5种【从普通到DCL演进4种、静态内部类】)单例模式详解

41 篇文章 0 订阅
24 篇文章 0 订阅

一、⭐⭐⭐概述🌙🌙🌙:

单例模式:某个类在整个系统种只能有一个实例对象可被获取和使用的代码模式,提供一个全局唯一的类的实例对象给外部调用,例如:代表jvm运行环境的Runtime类。
要点如下:
1、保证类只有唯一一个实例对象:则要求存储该实例对象的是一个静态类变量;
2、保证只能在该类的内部创建实例对象,其他地方不允许创建:则要求该类的构造器私有化;
3、保证外部能访问获取到这个唯一的实例对象:
1)直接暴露public static公共静态类变量
2)静态类变量定义为私有的,然后提供public statiic get公共静态的获取方法返回该静态类变量。
4、根据创建对象时机的不同,分饿汉式和懒汉式:
1)饿汉式:还没等到要用的时候,类加载的时候就生成;
2)懒汉式:第一次实际要使用这个实例对象的时候才生成。
5、若不允许修改,则建议定义成final的,避免他处获取后对其做修改

二、⭐⭐⭐饿汉式单例模式有三种实现方式🌙🌙🌙:

1、静态常量直接实例化(代表jvm运行环境的Runtime类生成单例,采用的就是这种实现方式,简洁直观);
2、枚举类(同1,虽然写法不同,但是实际原理相同,最简洁);
3、静态代码块(适合复杂的场景,如从配置文件读取所需参数)。
总结:饿汉式单例模式,由于在类加载的时候就完成实例化,所以避免了线程同步问题(运行期)。

三、⭐⭐⭐懒汉式单例模式有五种实现方式🌙🌙🌙:

1、懒汉式版本1(非线程安全);
2、懒汉式版本2(同步方法实现线程安全,但效率很低);
3、懒汉式版本3(同步代码块实现线程安全,但效率依旧较低);
4、懒汉式版本4(DCL(Double Check Lock),线程安全效率较高,但由于synchronized无法避免jvm优化时可能出现因指令重排导致的乱序执行,可能会遇到拿到的实例对象尚未被正确初始化的问题,这时可以利用volatile阻止指令重排的特点来解决);
5、懒汉式版本5 静态内部类(内部类被加载和初始化时才会创建对象,即调用时 )
总结:懒汉式单例模式,由于不是在类加载的时候就完成实例化,所以有可能会出现线程同步问题(运行期),需要设法解决。

四、⭐⭐⭐饿汉式代码 Hungry.java🌙🌙🌙

/1、静态常量直接实例化(代表jvm运行环境的Runtime类生成单例,采用的就是这种实现方式,简洁直观);
class HungrySigleton1 {
	private HungrySigleton1(){
	}
	private final static HungrySigleton1 INSTANCE = new HungrySigleton1();
	public static HungrySigleton1 getInstance(){
		return INSTANCE;
	}
}

//2、枚举类(最简洁);
enum HungrySigleton3{
	INSTANCE;
	private HungrySigleton3() {
	}
}

//3、静态代码块(适合复杂的场景,如从配置文件读取所需参数)。
class HungrySigleton2 {
	private HungrySigleton2(String info){System.out.println(info);}
	private  static HungrySigleton2 INSTANCE =null;
	static {
		Properties prop = new Properties();
		InputStream inStream = HungrySigleton2.class.getClassLoader().getResourceAsStream("project.properties");
		try {prop.load(inStream);} catch (IOException e) {e.printStackTrace();}
		String info =(String) prop.get("info");
		//扩展:读取配置文件的几种方式 1、Properties继承自Hashtable 2、ResourceBundle 3、Spring种利用ApplicationContext加载xml文件
		 INSTANCE = new HungrySigleton2(info);
	}
	public static HungrySigleton2 getInstance(){
		return INSTANCE;
	}
}
public class Hungry{
	public static void main(String[] args) {
		HungrySigleton1 ins1 = HungrySigleton1.getInstance();
		HungrySigleton2 ins2 = HungrySigleton2.getInstance();
		HungrySigleton3 ins3 = HungrySigleton3.INSTANCE;
	}
}

五、⭐⭐⭐懒汉式代码 Lazy.java🌙🌙🌙

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

//2、懒汉式版本2(同步方法实现线程安全,但效率很低);
class LazySigleton2 {
	private LazySigleton2(){
	}
	private  static LazySigleton2 INSTANCE =null;
	public synchronized static LazySigleton2 getInstance(){
		if(null == INSTANCE){
			try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}
			INSTANCE = new LazySigleton2();
		}
		return INSTANCE;
	}
}

//3、懒汉式版本2(同步代码块提供了一定效率,但存在线程安全问题);
class LazySigleton3 {
	private LazySigleton3(){
	}
	private  static LazySigleton3 INSTANCE =null;
	public  static LazySigleton3 getInstance(){
		if(null == INSTANCE){
			try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}
			synchronized(INSTANCE){
				INSTANCE = new LazySigleton3();
			}
		}
		return INSTANCE;
	}
}

//4、懒汉式版本2(DCL(Double Check Lock),线程安全效率较高,但由于synchronized无法避免jvm优化时可能出现的乱序执行,可能会遇到拿到的实例对象尚未被正确初始化的问题,这时可以利用volatile来解决);
class LazySigleton4 {
	private LazySigleton4(){
	}
	private  static volatile LazySigleton4 INSTANCE =null;
	public  static LazySigleton4 getInstance(){
		if(null == INSTANCE){
			try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}
			synchronized(INSTANCE){
				if(null == INSTANCE){
					INSTANCE = new LazySigleton4();
				}
			}
		}
		return INSTANCE;
	}
}
//5、静态内部类(内部类被加载和初始化时才会创建对象,即调用时)
class LazySigleton5 {
	private LazySigleton5(){
	}
	private static class Inner{
		 private final static LazySigleton5 INSTANCE = new LazySigleton5();
	}
	public static LazySigleton5 getInstance(){
		return Inner.INSTANCE;
	}
}

public class Lazy {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService exec = Executors.newFixedThreadPool(2);
		Callable task = new Callable(){
			@Override
			public Object call() {
				LazySigleton1 instance = LazySigleton1.getInstance();
				System.out.println(Thread.currentThread().getName()+instance);
				return instance;
			}
		};
		Future f1 = exec.submit(task);
		Future f2 = exec.submit(task);
		LazySigleton1 l1 = (LazySigleton1) f1.get(),l2 = (LazySigleton1) f2.get();
		System.out.println("l1:" + l1);
		System.out.println("l2:" + l2);
		System.out.println(l1==l2);
		exec.shutdown();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dylanioucn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值