博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
单例模式
阅读量:6433 次
发布时间:2019-06-23

本文共 2246 字,大约阅读时间需要 7 分钟。

  • 定义

单例模式确保一个类仅仅有一个实例,并提供一个全局訪问点

  • 解释

从定义能够看出。特点是这个类仅仅有一个实例。

那么,为什么要这么做呢?原因在于,有些时候,这个类仅仅有一个实例会节约资源,或者仅仅有一个实例才干保证整个程序执行正确,一致。

比如:线程池。缓存,对话框,日志对象等等 。

  • 演示样例
class Singleton {
private static Singleton singleton; private Singleton() {
} public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton(); } return singleton; }}

这是单例的经典使用方式:

  • 一个 private static 对象
  • 构造器设置为 private
  • 一个 public static 方法提供全局訪问点

開始的时候。事实上我比較困惑为什么不在 singleton 声明处直接实例化对象,后来明确了。这是一种延迟实例化的手段,保证仅仅在须要时才实例化。假设直接在声明时实例化,那么仅仅要类载入了,即使不须要对象,也会对它进行实例化。

另外,这个经典使用方式事实上是有问题的,对照后面 Tomcat 中的应用场景。你可能会发现问题所在。

在 Tomcat 中,就有一个单例模式,它是 org.apache.catalina.tribes.util.StringManager 类。

在 Tomcat 中。会有很多地方须要对错误消息进行处理。我们使用 StringManager 类来管理这些错误消息。

错误消息首先不能硬编码到代码中,否则须要提供国际化支持时,就会非常痛苦。错误消息须要定义在配置文件里。

Tomcat 为每一个包 (package) 都提供了三种语言的错误消息配置文件。每一个包内都有非常多类,我们不是必需为每一个类都生成一个 StringManager类,由于它们共享同一个配置文件。所以,一个包仅仅须要一个 StringManager 对象就好了。

我们怎么为一个包生成一个StringManager 呢? Tomcat 在 StringManager 内部保存着全部包的 StringManager 实例,你须要一个实例时,仅仅须要提供包名。调用 StringManager 的相应方法。就会返回与此包名相应的 StringManager 实例。以下是相关的代码,一目了然。

public class StringManager {
private StringManager(String packageName) {
...}private static final Hashtable
managers =new Hashtable<>();/*** Get the StringManager for a particular package. If a manager for* a package already exists, it will be reused, else a new* StringManager will be created and returned.** @param packageName The package name*/public static final synchronized StringManager getManager(String packageName) {
StringManager mgr = managers.get(packageName); if (mgr == null) {
mgr = new StringManager(packageName); managers.put(packageName, mgr); } return mgr;}

使用了一个 Hashtable 来保存 managers,每次通过 getManager 方法。通过包名訪问,假设訪问不到,就为此包新生成一个StringManager 实例。

有没有注意到 getManager 方法被 synchronized 修饰?这就是之前我们举的经典演示样例时说的问题。在使用单例时。仅仅有一个对象。这个对象可能是被多个线程共享的。假设不同步,就可能会出现数据不一致的情况。

比如,两个线程同一时候调用了getManager。訪问同一个包名。正确的运行是,当中一个线程第一次调用时,mgr 为空。此时生成一个 StringManager。

第二个线程调用时,mgr 就不为空了。可是,假设不同步。那么当第一个线程通过了 if(mgr == null) 时,此时线程被切换了,这时,第二个线程也会通过 if(mgr == null) ,这样就导致同一个包,生成了两个 StringManager

  • 扩展阅读

关于单例模式与线程安全。建议阅读一下这篇文章:

关于单例模式的其他实现方式,能够阅读

转载地址:http://nnxga.baihongyu.com/

你可能感兴趣的文章
文本处理工具grep及正则表达式
查看>>
Intel VT-x处于禁用状态
查看>>
用什么软件可以修改PDF文件,软件的操作方法
查看>>
如何精简企业主数据“裹脚布”
查看>>
& 号和管道符号(|)在不同场景下的使用方法
查看>>
curl 浏览器模拟请求实战
查看>>
多个VLAN中的vrrp备份组配置举例
查看>>
运维自动化之使用PHP+MYSQL+SHELL打造私有监控系统(六)
查看>>
interlib在tomcat7.0的安装
查看>>
水晶报表在大型WEB内部管理系统里的滑铁卢
查看>>
我的友情链接
查看>>
Git学习
查看>>
trove 基于 centos7 制作 mysql5.6 镜像
查看>>
结合i节点和数据块分析linux中软链接和硬链接的区别
查看>>
Heartbeat crm的配置
查看>>
Stream
查看>>
我的友情链接
查看>>
Windows Server 2012_Install_Guide
查看>>
ISA Server搭建站点对站点×××
查看>>
我的友情链接
查看>>