java 设计模式之单例模式
作者:ionetwogo 发布时间:2021-10-07 22:00:46
java 设计模式之单例模式
前言:
在软件开发过程中常会有一些对象我们只需要一个,如:线程池(threadpool)、缓存(cache)、对话框、偏好设置等。这些对象如果制造出多个实例的话可能会导致一些不必要的麻烦,如:程序行为异常、资源使用过量等。这时单例模式就可以确保一个类只有一个实例,并提供全局访问点。下面是从简单的单例类来探讨该用何种方法实现单例模式。
/**
* 最经典的单例类
*/
public class Singleton {
// 设置成静态变量来记录Singleton的唯一实例
private static Singleton singleInstance;
private Singleton(){
// 构造方法声明为私有的,这样只能在Singleton类中才能调用此构造方法
}
/*
* 获取Singleton对象,如果还未实例化则实例化一个对象并返回这个实例
*/
public static Singleton getInstance(){
if (singleInstance == null) {
singleInstance = new Singleton();
}
return singleInstance;
}
// 其他方法
}
从上面的例子可以看出Singleton类自己管理这个类的实例化过程,而且提供了全局访问点,就是设置成静态的getInstance()方法,在其他类要使用Singleton时它会返回一个实例。这中单例模式有个优点就是延迟实例化,简单地说延迟实例化就是延迟初始化,在类需要时才创建其实例,而不是在开始加载这个类时就创建出一个实例,这样的好处是可以避免性能的浪费。例如有些对象无需程序一开始就使用,或者其在程序执行的过程中就没有使用过。但是此例子却又一个缺点,那就是线程不够安全。因为如果有多个线程同时执行到getInstance()方法,而Singleton又还未new Singleton()一个实例,那么线程就会都认为singleInstance为null,就都会实例化Singleton,这时就会产生多个Singleton实例,明显不符合单例模式的初衷。那么接下来可能要做的就是对其进行改进
public class SingletonA {
private static SingletonA singletongA;
private SingletonA(){
}
/*
* 增加synchronized关键字把getSingletonA方法变为同步方法
*/
public static synchronized SingletonA getInstanceA(){
if (singletongA == null) {
singletongA = new SingletonA();
}
return singletongA;
}
// 其他方法
}
从这个例子上看增加了synchronized可以使getInstanceA()变成一个同步的方法,这时线程在进入这个方法之前就需要等待其他线程离开这个方法才能进入,也就使得该方法只能同时存在一个线程在执行它。
可能差不多问题解决了,但是要知道同步方法是会影响程序执行效率的,在此例子中我们只是为了解决第一个例子中第一次执行getInstance()方法不会产生多个实例,而这个例子中却会导致每次需要实例时都会调用getInstanceA()同步方法,而在已经有实例之后的调用synchronized就会是累赘,因为我们已经无需担心这个单例类会再次被创建出新的实例。因此我们还需要做一下改进。
既然上面说到延迟实例化,那么如果是不用的话那就简单多了。
public class SingletonB {
// 在静态初始化器(static initializen)中创建单例,保证线程安全
private static SingletonB singletonB = new SingletonB();
private SingletonB(){
// 构造函数
}
public static SingletonB getInstaceB(){
// 已经实例化了,直接使用它
return singletonB;
}
}
上面的这种做法是在JVM加载这个类时马上创建一个实例,因为JVM会在线程访问这个实例之前就创建出该实例,因此线程是安全的。但这相较于延迟实例化而言可能会出现资源的浪费。而且如果此类较大的情况下会时程序初始化时间加长。
那么是否可以在使用用延迟实例化的同时又不会造成线程不安全且增加访问效率呢。接下来就用双重检查加锁来改进一下。
/**
* 双重锁单例模式
*/
public class SingletonC {
private volatile static SingletonC singletonC;
private SingletonC(){
}
public static SingletonC getInstanceC(){
if (singletonC == null) {
synchronized (SingletonC.class) {
if (singletonC == null) {
singletonC = new SingletonC();
}
}
}
return singletonC;
}
}
上面的例子是先检查实例,如果不存在则进入同步区块,进入同步区块之后再次检查,如果还是null才会创建实例,因而singletonC = new SingletonC()只会执行一次,而之后调用getInstanceC()时就因为有实例直接返回,所以除了第一次调用时会走同步,而之后便不会如第二个例子那样每次都会走同步方法。这样就可以使得执行getInstanceC()的时间减少。想必这里会发现有个volatile关键字,其作用是使得singletonC被初始化后对所有线程可见,多个线程可以正确地处理这个SingletonC变量。但要注意的:volatile关键字只能在Java 5及其之后使用,如果在此版本之前会导致这个双重检查失效。
在使用单例模式时,如果有多个类加载器(classloader)时需要自行指定类加载器,并指定用一个类加载器。因为每个类加载器都定义了一个命名空间,不同的类加载器可能会加载同一个类,从而导致单例类创建出多个实例。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
来源:http://blog.csdn.net/qq_15128547/article/details/53205727


猜你喜欢
- 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供
- 给对象中的包装类设置默认值处理方法如下主要适用于,对象中使用了包装类,但是不能给null需要有默认值的情况/**
- 概念异常处理的概念起源于早期的编程语言,如 LISP、PL/I 和 CLU。这些编程语言首次引入了异常处理机制,以便在程序执行过程中检测和处
- 本文实例为大家分享了QT实现用户登录注册的具体代码,供大家参考,具体内容如下#include "widget.h"#in
- 本文这个实例通过前面学过的Paint、Canvas等2D绘画技术来实现一个简单的Android的绘图板。具体实现代码:创建一个名为DrawV
- 如下所示:import java.util.*;public class Main{public static void main(Stri
- RESTful 一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设
- SEATA概要seata 是alibaba 出的一款分布式事务管理器,他有侵入性小,实现简单等特点。我们能够使用seata 实现分布式事务管
- 预览:捕捉声卡输出:实现音频可视化, 第一步就是获得音频采样, 这里我们选择使用计算机正在播放的音频作为采样源进行处理:NAudio 中,
- 默认spring只在发生未被捕获的runtimeexcetpion时才回滚。最笨的办法:代码级控制:TransactionAspectSup
- 1.下载JRebel and XRebel for Intellij插件2. 激活请查看这个文章http://www.cicoding.cn
- 前言:JSON 是轻量级的数据交换格式,很常用,尤其是在使用 Ajax 时,在后台将数据封装为 JSON 字符串更是常见。之前在做项目的时候
- 前几天刚好有需求要把emoji对应的Unicode编码转换成文字,比如1f601对应的这个笑脸😁,但没有找到C#的把1f601转换成文字的方
- 指纹识别作为最新兴起的用户身份验证机制,已经被越来越多的应用程序所采用,相比传统的密码九宫格等验证方法,指纹识别更加安全,如今越来越多的安卓
- springboot的最强大的就是那些xxxAutoconfiguration,但是这些xxxAutoConfiguration又依赖那些s
- SpringDataJpa创建中间表//fetch=FetchType.EAGER 关闭懒加载 相当于hibernate中的lazy=fal
- 协程属于Kotlin中非常有特色的一项技术,因为大部分编程语言中是没有协程这个概念的。那么什么是协程呢?它其实和线程有点相似,可以简单地将它
- 前言之前几篇我们介绍了贝塞尔曲线的原理、绘制曲线和动效实现,这些都是代码预设好的,如果我们要根据需要自行绘制曲线,就需要使用交互来实现了。本
- Java 8的18个常用日期处理一、简介伴随lambda表达式、streams以及一系列小优化,Java 8 推出了全新的日期时间API。J
- 说明:本文记录如何在Idea下,利用Maven管理项目,并整合SSM(Spring + Spring MVC +Mybatis)框架,实现简