单例模式
2016-04-06 13:42
218 查看
定义
单例模式确保一个类仅仅有一个实例,并提供一个全局訪问点
解释
从定义能够看出。特点是这个类仅仅有一个实例。
那么,为什么要这么做呢?原因在于,有些时候,这个类仅仅有一个实例会节约资源,或者仅仅有一个实例才干保证整个程序执行正确,一致。
比如:线程池。缓存,对话框,日志对象等等 。
演示样例
这是单例的经典使用方式:
一个 private static 对象
构造器设置为 private
一个 public static 方法提供全局訪问点
開始的时候。事实上我比較困惑为什么不在 singleton 声明处直接实例化对象,后来明确了。这是一种延迟实例化的手段,保证仅仅在须要时才实例化。假设直接在声明时实例化,那么仅仅要类载入了,即使不须要对象,也会对它进行实例化。
另外,这个经典使用方式事实上是有问题的,对照后面 Tomcat 中的应用场景。你可能会发现问题所在。
在 Tomcat 中,就有一个单例模式,它是
在
Tomcat 中。会有很多地方须要对错误消息进行处理。我们使用
错误消息首先不能硬编码到代码中,否则须要提供国际化支持时,就会非常痛苦。错误消息须要定义在配置文件里。
Tomcat 为每一个包 (package) 都提供了三种语言的错误消息配置文件。每一个包内都有非常多类,我们不是必需为每一个类都生成一个
我们怎么为一个包生成一个
Tomcat 在
使用了一个
有没有注意到 getManager 方法被
比如,两个线程同一时候调用了
为空。此时生成一个 StringManager。
第二个线程调用时,mgr 就不为空了。可是,假设不同步。那么当第一个线程通过了
扩展阅读
关于单例模式与线程安全。建议阅读一下这篇文章:
深入浅出单实例Singleton设计模式
关于单例模式的其他实现方式,能够阅读
单例模式的七种写法
单例模式确保一个类仅仅有一个实例,并提供一个全局訪问点
解释
从定义能够看出。特点是这个类仅仅有一个实例。
那么,为什么要这么做呢?原因在于,有些时候,这个类仅仅有一个实例会节约资源,或者仅仅有一个实例才干保证整个程序执行正确,一致。
比如:线程池。缓存,对话框,日志对象等等 。
演示样例
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<String, StringManager> 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。
扩展阅读
关于单例模式与线程安全。建议阅读一下这篇文章:
深入浅出单实例Singleton设计模式
关于单例模式的其他实现方式,能够阅读
单例模式的七种写法
相关文章推荐
- 源码分析之LinkedList
- Json数据格式
- 网络爬虫开发技术——数据存储以及多线程
- C++ 二维码生成
- python学习过程-变量
- Apache实现主域名301自动跳转到www二级域名
- 欢迎使用CSDN-markdown编辑器
- Android5.0以太网流程源码情景分析
- Linux下动态链接库的创建和使用
- #4变量的包装类#
- 保存数据到手机内存代码优化(QQ登录保存密码)
- 秒杀Sublime Text的微软开源代码编辑工具Visual Studio Code
- 关于jquery的$.extend(true,{},m,n)的一个小问题
- java学习笔记(三)java接口总结
- [AFNetworking练习1]Post方式提交json返回json
- 使用源码编译wxpython-基于python2.7
- 使用源码编译wxpython-基于python2.7
- 【虚拟化实战】存储设计之七Block Size
- Leetcode 86. Partition List
- SSD 下的 MySQL IO 优化