设计模式:单例模式多种实现及应用场景Java版
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了设计模式:单例模式多种实现及应用场景Java版,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4025字,纯文字阅读大概需要6分钟。
内容图文
开篇
设计模式对于很多小伙伴来说都是它认识你,但是你不认识它,设计模式可以帮助我们简化代码,提高代码的复用率,减少代码的耦合性,以及增加代码的重复利用性,但是设计模式并非是好用的代言,有些时候也会给我们代来很多问题,比如简单的判断语句会变成复杂的多类关联,也会引发一些安全问题,比如今天要说的单例模式。
基本介绍
单例模式(Singleton Pattern)是Java中最简单的设计模式之一(暗藏玄机)。属于创建模式之一,提供了一种创建对象的最佳方式。一个单一的类,负责创建自己的对象,同时保证只有单个对象被创建,对外提供唯一的方法来获取该类的对象,并且不需要实例化对象。因此可以总结出以下几点:
- 只能有一个实例(注意防止并发)。
- 实例必须是自己创建的。
- 必须给其他对象这一实例。
主要解决
一个被全局使用的类,被频繁的创建,当你想控制资源,节省资源时,你就要使用单例模式。
关键代码
- 默认构造函数要私有。
- 提供对外获取对象的唯一方法。
使用场景
- Spring中Bean容器管理的对象,默认下就是通过单例构建对象
- 系统中ID生成器,通常采用单例模式创建出对象
- 比如定时任务中,发现任务和触发执行器执行的类,一般都设计成单例模式获取(频繁使用)
缺点
- 没有接口,不能被继承
- 控制不好会有并发问题,除了枚举类之外,可以被反射获取新的实例
- 单一原则下,类应该只关心内部,不应该关心外部的创建,违背单一原则
具体实现并带有优缺点分析
1、饿汉式
/**
* 饿汉式
* 利用classload上来初始化实例,解决并发问题
* 但是此方法比较大的问题就是,当初始化单利比较耗时,或者很久不会使用的时候,浪费内存
* 是最长用方案
*/
public class SingleObject {
//单例模式必然是上来就私有化
private SingleObject() {
}
//创建一个唯一的类对象
private static SingleObject instance = new SingleObject();
//提供一个获取的方法
public static SingleObject getInstance() {
return instance;
}
}
2、懒汉式,不考虑并发
/**
* 因此引出懒汉式,节省内存
* 但是此情况又会出现线程并发问题
* 在判断 instance == null 的时候可能出现并发,多线程同时到达new
*/
class SingleObjectLazy {
//依然是上来私有构造
private SingleObjectLazy() {
}
//创建静态对象变量,不初始化
private static SingleObjectLazy instance;
//使用时在初始化
public static SingleObjectLazy getInstance() {
if (instance == null) {
instance = new SingleObjectLazy();
}
return instance;
}
}
3、懒汉式,加锁
/**
* 由于并发引出加锁,
* 但是很难出现同时获取instance而且还是为空的情况
* 一旦创建后,不在需要锁住
* 此时就会造成效率低下
*/
class SingleObjectSyncLazy {
private SingleObjectSyncLazy() {
}
private static SingleObjectSyncLazy instance;
public static synchronized SingleObjectSyncLazy getInstance() {
if (instance == null) instance = new SingleObjectSyncLazy();
return instance;
}
}
4、懒汉式,双重检查代替方法锁,提高效率,防止指令重排加入volatile
/**
* 使用双重检查机制
* 只有当并发null的时候才需要进入加锁,此时并发的概率很小
* 还是有问题的,不加上 volatile修饰的话,会出指令重排
* 同时 synchronized 只保单线程的结果正确,不会保证指令重排,
*/
class SingleObjectSyncLazyDouble {
private SingleObjectSyncLazyDouble() {
}
//防止指令重排
private volatile static SingleObjectSyncLazyDouble instance;
public static SingleObjectSyncLazyDouble getInstance() {
if (instance == null) { //只有并发null的时候进入加锁
synchronized (SingleObjectSyncLazyDouble.class) {
//as-if-serial synchronized 只会保证单线程内执行操作结果,指令依然会重排
if (instance == null) { //不加,就会直接创建两个
/*此处会出现指令重排
* instance = new SingleObjectSyncLazyDouble();
* 1、开辟内存
* 2、实例化
* 3、引用指向
* 不加volatile 就会出现混乱效果,导致先引用,这时候第二线程刚好到达第一处检查,
* 直接走人了。就出现了大问题
* */
instance = new SingleObjectSyncLazyDouble();
}
}
}
return instance;
}
}
5、懒加载、静态内部类实现。
/**
* 静态内部类的使用,静态内部类内部的方法是在第一次调用的时候才会加载,因此可以避免一上来就被初始化的问题
* 也是一种懒加载的形式
*/
class SingleObjectStaticLazy {
private SingleObjectStaticLazy() {
}
private static class StaticClass {
private static SingleObjectStaticLazy instance = new SingleObjectStaticLazy();
}
public static SingleObjectStaticLazy getInstance() {
return StaticClass.instance;
}
}
6、枚举
以上都可以通过反射获取新的实例,枚举类被反射会直接触发异常
该方法在1.5才开始引入,不受众,不过是小黄书推荐的方式。
/**
* 枚举
*/
public enum SingleObject {
INSTANCE;
}
结束
以上就是单例模式创建的方式,优点缺点,希望可以对大家有所帮助 。
内容总结
以上是互联网集市为您收集整理的设计模式:单例模式多种实现及应用场景Java版全部内容,希望文章能够帮你解决设计模式:单例模式多种实现及应用场景Java版所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。