java:单例模式的五种实现方式[通俗易懂]

java:单例模式的五种实现方式[通俗易懂]基于java实现到单例模式

大家好,又见面了,我是你们的朋友全栈君。

1. 概述

java单例模式是一种常见的设计模式。

单例模式有以下特点:

  1. 单例类只能有一个实例;
  2. 单例类必须自己创建自己的唯一实例;
  3. 单例类必须给所有其他对象提供这一实例;

2. 优缺点

  • 优点:由于单例模式只生成了一个实例,所以能够节约系统资源,减少性能开销,提高系统运行效率。
  • 缺点:因为系统中只有一个实例,导致了单例类的职责过重,违背了“单一职责原则”,同时不利于扩展。

3. 单例模式实现方式

常见的单例模式实现方式有五种:饿汉式懒汉式双重检测锁静态内部类枚举单例

3.1 饿汉式

public class SingletonDemoInHunger { 
   
	
	// 私有实例,类初始化就加载
	private static SingletonDemoInHunger instance = new SingletonDemoInHunger();
	
	// 私有构造方法
	private SingletonDemoInHunger() { 
   }
	
	// 公共的、静态的获取实例方法
	public static SingletonDemoInHunger getInstance() { 
   
		return instance;
	}
}

饿汉式

  • 类加载时就初始化,浪费内存,不能延迟加载
  • 基于 classloader 机制避免了多线程的同步问题,线程安全
  • 没有加锁,调用效率高

3.2 懒汉式

public class SingletonDemoInLazy { 
   
	
	// 私有实例,初始化的时候不加载(延迟加载)
	private static SingletonDemoInLazy instance;
	
	// 私有构造
	private SingletonDemoInLazy() { 
   }
	
	// 公共获取实例方法(线程不安全)
	public static SingletonDemoInLazy getInstance() { 
   
		if(instance == null ) { 
    // 使用的时候加载
			instance = new SingletonDemoInLazy();
		}
		return instance;
	}
}

上面这种写法,是线程不安全的,但是可以做到延迟加载

下面是线程安全的懒汉模式:

public class SingletonDemoInLazy { 
   
	
	// 私有实例,初始化的时候不加载(延迟加载)
	private static SingletonDemoInLazy instance;
	
	// 私有构造
	private SingletonDemoInLazy() { 
   }
	
	// 公共获取实例方法(线程安全,调用效率低)
	public synchronized static SingletonDemoInLazy getInstance() { 
   
		if(instance == null ) { 
   
			instance = new SingletonDemoInLazy();
		}
		return instance;
	}
}

上面代码中,通过关键字synchronized声明公共的获取实例的方法getInstance(),可以确保线程安全,能做到延迟加载,但是效率不高

3.3 double-checked locking(双重检查锁)

public class SingletonDemoInDoubleCheckLock { 
   
	
	// 私有实例,volatile关键字,禁止指令重排。
	private volatile static SingletonDemoInDoubleCheckLock instance;
	
	// 私有构造
	private SingletonDemoInDoubleCheckLock() { 
   }
		
	// 公共获取实例方法(线程安全)
	public static SingletonDemoInDoubleCheckLock getInstance() { 
   
		if(instance == null ) { 
    // 一重检查
			synchronized (SingletonDemoInDoubleCheckLock.class) { 
   
				if(instance == null) { 
    // 二重检查
					instance = new SingletonDemoInDoubleCheckLock();
				}
			}
		}
		return instance;
	}
}

在加锁之前判断是否为空,可以确保 instance 不为空的情况下,不用加锁,可以直接返回。

加锁之后,还需要判断 instance 是否为空,是为了防止在多线程并发的情况下,会实例化多个对象。例如:线程 a 和线程 b 同时调用 getInstance 方法,假如同时判断 instance 都为空,这时会同时进行抢锁。假如线程 a 先抢到锁,开始执行 synchronized 关键字包含的代码,此时线程 b 处于等待状态。线程 a 创建完新实例了,释放锁了,此时线程 b 拿到锁,进入 synchronized 关键字包含的代码,如果没有再判断一次 instance 是否为空,则可能会重复创建实例。

双重检查锁

  • 双重判断,延迟加载;
  • 线程安全;
  • JDK 版本要求1.5起。

3.4 静态内部类

public class SingletonDemoInStaticInnerClass { 
   
	
	// 静态内部类
	private static class InnerClass{ 
   
		// 初始化实例
		private final static SingletonDemoInStaticInnerClass INSTANCE = new SingletonDemoInStaticInnerClass();
	}
	
	// 私有构造
	private SingletonDemoInStaticInnerClass() { 
   }
	
	// 公关获取实例方法(线程安全,延迟加载)
	public static SingletonDemoInStaticInnerClass getInstance() { 
   
		return InnerClass.INSTANCE;
	}
}

静态内部类

  • 利用了classloader机制来保证初始化 instance 时只有一个线程,线程安全
  • 只有通过显式调用 getInstance 方法时,才会显式装载静态内部类,从而实例化instance延迟加载

3.5 枚举

public enum SingletonEnum { 
   
	
	// 枚举元素本身就是单例 
	INSTANCE;
	
	
	// 其他要执行的方法
	public void sayHello() { 
   
		System.out.println("你好");
	}
	......
}

枚举:这是实现单例模式的最佳方法。它更简洁,不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。但是不是延迟加载的。

如何选用哪种方式实现单例模式?
一般情况下,不建议懒汉式,建议使用饿汉式;只有在要明确实现延迟加载效果时,才会使用静态内部类;如果涉及到反序列化创建对象时,可以尝试使用枚举;如果有其他特殊的需求,可以考虑使用双重检查锁。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/156328.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • python的多线程是否没有用了[通俗易懂]

    python的多线程是否没有用了[通俗易懂]python的多线程是否就完全没有用了呢?相同的代码,为何有时候多线程会比单线程慢,有时又会比单线程快? 这主要跟运行的代码有关: 1、 CPU密集型代码 (

    2022年7月3日
    36
  • 垃圾邮件分类实战(SVM)

    1.数据集说明trec06c是一个公开的垃圾邮件语料库,由国际文本检索会议提供,分为英文数据集(trec06p)和中文数据集(trec06c),其中所含的邮件均来源于真实邮件保留了邮件的原有格式和

    2021年12月30日
    67
  • navicat15激活码linux_在线激活

    (navicat15激活码linux)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.htmlS32PGH0SQB-eyJsaWN…

    2022年3月26日
    64
  • 黑群晖vmm专业版_教你群晖用自带的VMM虚拟机安装精简版win10系统教程

    黑群晖vmm专业版_教你群晖用自带的VMM虚拟机安装精简版win10系统教程教你群晖用自带的VMM虚拟机安装精简版win10系统教程;V;q”X,~+K6O’ra,a+b新手请严酷依照我的操纵履行,几近每个步调都截图了,100%纯小白教程!2^%P4U:{$IE”?,V7S9p&d0D&s&?安装VMM虚拟机:!N3K&U&h$\+W1、进入群晖系统后,在套件中心,找到…

    2022年9月2日
    4
  • aix dump_coredump文件分析

    aix dump_coredump文件分析Usingthedumpextractor,jextractTousethefullfacilitiesofthedumpviewer,youmustfirstrunthe jextract toolonthesystemdump.The jextract toolobtainsplatform-specificinformatio…

    2022年9月27日
    5
  • 软件缺陷,缺陷报告怎么写_缺陷报告通常包括哪些内容

    软件缺陷,缺陷报告怎么写_缺陷报告通常包括哪些内容软件缺陷软件缺陷:常常又被叫做Bug。所谓软件缺陷,即为计算机软件或程序中存在的某种破坏正常运行能力的问题、错误,或者隐藏的功能缺陷。缺陷的存在会导致软件产品在某种程度上不能满足用户的需要。从软件测试观点出发,软件缺陷有以下五大类:功能缺陷、系统缺陷、加工缺陷、数据缺陷、代码缺陷软件类别:缺陷的表现形式不仅体现在功能的失效方面,还体现在其他方面。主要类型有:软件没有实现产品规格说明所…

    2022年9月18日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号