Singleton可能是所有设计模式中最简单的设计模式啦。它是如此的简单,以至于当我们看着它的UML图的时候会为终于没有了恼人的连线而雀跃,我们
也不用去记忆并体会它有多么强大的功能、多么高深的实现技巧。使用它的理由只有一个――得到一个Class的唯一的Object。它的实现是如此简单,以
至于你会怪我把它的Code列在下面是在浪费服务器空间。但是,天下并没有这么爽的事儿,当Singleton遇到multi-threading,一些
不为人所知的陷阱悄悄的浮上了水面,我们不得不小心应对它们。一下的示例以Java作为编程语言,讨论了multi-threading下实现
Singleton的策略,并顺便告诉你几个关于Java实现Singleton的、你可能不知道的tricky things。
<!---->public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
这是典型的Singleton的实现,在single-threading下,它没有任何问题。但是,你能告诉我在multi-threading下,可
能会发生什么事情么?multi-threading是顽皮的小孩,它不保证各个线程执行的顺序,所以,会有一种可能,if
(uniqueInstance == null)这个判断会在不同的线程中连续执行。让我们看看最简单的、只有两个线程的情况:
thread
1
thread
2
uniqueInstance
if(uniqueInstance ==
null)
null
if(uniqueInstance ==
null) null
uniqueInstance = new Singleton();
new object
uniqueInstance = new Singleton(); new object
看到了么?产生了两个不同的Object!这不一定永远是坏事,比如这是一个在线购物的控制系统,那么你可能会用一件衣服的钱买到两件衣服,虽然也有可能
是你付了钱,但是没得到衣服,但是概率是50%对50%的,也不是什么大不了的事儿~但是,如果这是一个铁路调度控制系统呢?火车也许会相撞。如果这是一
个核反应堆的控制系统呢?一个城市可能就变成废墟了(当然,也许你希望这发生在日本)。
OK!我们达成了一致,这确实是个大问题。我们怎么解决它?“我们可以用synchronized!”有人兴奋的叫到:“真是个好主意!”好,我们来试试看~
<!---->public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {}
public static synchronized Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
好样的!现在同一时刻只有一个线程能调用getInstance()方法,不会存在城市被炸平的悲剧了,我们拯救了几百万人(上海的话,一千多万人)!我
代表他们感谢你,但是,过不了多久就有人会站出来抱怨:“为什么系统的速度变慢了?”这些没良心的人们,这么快就忘记了这段code拯救了他们的性命,竟
然抱怨起了这么小的问题!愤愤之余,你开始思考速度变慢的原因。
啊,synchronized,它使得原本并行的访问变成了串行,这是性能的瓶颈,有什么办法可以解决吗?当然,有人站了出来:“我有投机取巧的方法。”
<!---->public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
}
问题解决了~JVM会在所有线程之前先实例化一个Object,所有的getInstance()调用都是在引用这个预先产生的Object,不会有任何的问题啦~
但是,完美主义的我们并不满意:“无论是否使用这个Class,都会预先产生一个Object,这很不优雅!”那我们就看看优雅的解决方案。考虑一下
multi-threading下出现错误的原因,并不是因为不同的线程同时调用了getInstance()方法,而是if
(uniqueInstance ==
null)出现了意想不到的排列,也就是说,只有在产生Object的时候,才会有multi-threading的问题,当
uniqueInstance != null时,多少个线程都不会有问题。因此,我们得到了结论:只需要对创建Object的code上锁就可以了。
<!---->public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
关键字volatile可以保证uniqueInstance可以被同时运行的若干个线程正确的修改,而getInstance()方法体中的写法则保证
了细力度的线程锁。注意,uniqueInstance == null被判断了两次,这是必要的,这种方法叫做Double-checked
locking。
噹噹噹噹~任务完成,Singleton不在惧怕multi-threading啦!让我们来看看关于Java实现Singleton的tricky things。
-
Double-checked locking最好只在Java 5中使用。在Java
1.4以及之前版本的诸多实现中,volatile关键字都被错误的实现,这会导致Double-checked locking的不正确执行。
-
在Java
1.2以及之前的版本中,JVM的垃圾回收器存在一个bug:当一个Singleton的Object不存在全局引用(即只有自身的instance变量
在引用这Object)的时候,垃圾回收器会回收这个Object。也就是说,在这种情况下,getIntance()会得到一个新的Object,这不会导致城市被炸平,但是会导致做了10年的核反应成果突然消失,当然不是我们想要的。
- Java允许不同的Class
Loader创建自己的Object,它们用namespace来区别这些Object。因此,当你的Singleton设计Class
Loader时,最好在获取Object的时候同时指定它的Class Loader。
分享到:
相关推荐
perl-Class-Singleton-1.4-6.el6.noarch.rpm perl-Class-Singleton-1.4-6.el6.noarch.rpm
DataSource的单态模式(SingleTon)程序---马克-to-win java视频 数据源 单态模式 dataSource Singleton
python库。 资源全名:django-singleton-admin-0.0.2.macosx-10.7-intel.exe
$this->app->singleton('cache.multi-memcached', function ($app) { $stores = []; foreach ($app['config']['cache.stores'] as $store => $config) { if ($config['driver'] === 'memcached') { $connector ...
离线安装包,亲测可用
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,亲测可用
在`singleton-pattern-master`这个压缩包中,可能包含了一个示例项目或者一个库,它演示了如何在Laravel中实现和使用单例模式。可能的目录结构包括源代码文件、配置文件、示例测试等,帮助开发者更好地理解和应用...
Bean配置它提供2个不同的单例ObjectMapper实例。 参见master-module/BeansConfiguration 为了验证它们是否为单例,请在module-1运行测试并检查打印的输出。多模块设置一个空的父模块,其中包含3个相互依赖的模块。...
以下是对"单例实现源码singleton-C++"的详细解析。 1. **静态成员变量法** 这是最常见的单例实现方式。在类中定义一个静态成员变量,该变量保存唯一的实例。例如: ```cpp class Singleton { public: static ...
在iOS开发中,Singleton(单例)是一种常见的设计模式,用于确保一个类在整个应用程序中只有一个实例存在,并提供全局访问点。Singleton模式的核心在于控制类的实例化过程,防止多个实例的产生,通常用于管理共享...
**PyPI 官网下载 | dask-actor-singleton-1.1.0.tar.gz** 在Python的世界里,PyPI(Python Package Index)是官方的软件仓库,它为开发者提供了发布和分享Python软件包的平台。`dask-actor-singleton-1.1.0.tar.gz`...
因为Java虚拟机(JVM)的类加载机制是线程安全的,当多个线程尝试同时加载同一类时,只会有一个线程成功,其他线程则会被阻塞,直到类加载完成。如果类加载过程耗时较长,那么其他线程可能会持续等待,从而引发饥饿...
private static final Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; } } ``` 2. **饿汉式(静态代码块)** 类加载时初始化...
标题 "hk2-multi-module-example" 提示我们这是一个关于如何利用 HK2 框架在多模块项目中的应用实例。描述中提到,这是一个使用多个 HK2 模块构建的“胖 jar”示例,这意味着它将所有依赖打包进了一个单一的可执行 ...
npm install node-singleton-event -save 如何使用 在要与另一个文件进行通信的每个文件中都需要它。 说些什么: var singletonevent = require('node-singleton-event'); singletonevent.emit('talk', 'hello ...
`once` 函数 `singleton` 确保类的实例化过程中只会创建一个实例,并且每次调用 `singleton` 都会返回同一个实例。 #### 全局访问点 为了提供一个全局访问点来获取单例实例,我们引入了 `SINGLETON_Accessor` 类。...