一次代码review引发的关于单例模式的思考
来源:互联网 发布:ubuntu 修改文件内容 编辑:程序博客网 时间:2024/06/11 17:13
一次代码调优中发现一个情况,即我在查看memcached的connection时,发现总是维持在100来个左右,当然这看似没什么问题,因为memcached默认connection有1024个。但是我想的是为什么会有100来个,因为我的memcachedclient的产生采用的是单例模式我定义了一个memcachedClientFactory类,主要代码如下:
MemcachedClientFactory{private MemcachedConnectionBuilder memcachedConnectionBuilder;private String servers;private static MemcachedClient memcachedClient;private MemcachedClientFactory(){}private MemcachedClientFactory(MemcachedConnectionBuilder memcachedConnectionBuilder, String servers){this. memcachedConnectionBuilder= memcachedConnectionBuilder;this.servers=servers;}public static MemcachedClient createClient(){if(memcachedClient==null){this.memcahcedClien= new MemcachedClient(memcachedConnectionBuilder.build(),AddrUtil.get(servers));}return this.memcahcedClient;}}}
回到最初的问题,为什么会有100多个连接?
上面这个写法真的能保证只产生一个连接?很显然是不能,为什么?多线程并发!问题就出在这里,当有多个线程同时进入createClient()方法时,而且刚好都判断为memcachedClient为null,这时候就产生了多个连接。哈,问题找到了。
改进:
public static synchronizd MemcachedClient createClient(){if(memcachedClient==null){this.memcahcedClien= newMemcachedClient(memcachedConnectionBuilder.build(),AddrUtil.get(servers));}return this.memcahcedClient;}
这样就ok了,改动很简单。程序是没有问题了,而且也能保证只有一个连接。
不过抛开这个问题,我们可以继续就如何解决单例模式下的并发问题深入思考一下。
我总结一下,要解决单例模式在并发下的问题,大概有三种方式:
1. 不使用延迟实例化,而是用提前实例化。
即程序改写为:
Public Class Singleton{private static Singleton instance=new Singleton();private Singleton(){};public static Singleton getInstance(){ return instance;}}这样做时,jvm在加载类时就立马创建了该实例,所以这样做的前提是,创建该实例的负担不大,我不比过多的考虑性能,并且我们确认该实例是一定会用到的。其实我前面的代码也完全可以使用这个方式:
MemcachedClientFactory{private MemcachedConnectionBuilder memcachedConnectionBuilder;private String servers;private static MemcachedClient memcachedClien= newMemcachedClient(memcachedConnectionBuilder.build(),AddrUtil.get(servers));private MemcachedClientFactory(){}private MemcachedClientFactory(MemcachedConnectionBuilder memcachedConnectionBuilder, String servers){this. memcachedConnectionBuilder= memcachedConnectionBuilder;this.servers=servers;}public static MemcachedClient createClient(){return this.memcahcedClient;}}}
不过,看上去似乎没有问题,但是有隐患,即一旦有人不小心调用了memcachedClient.shutdown()方法,那整个程序就无法再生出新的memcachedClient了。当然这是极端情况了,但是为了代码的健壮,可以再改为:
public static MemcachedClient createClient(){if(memcachedClient==null){this.memcahcedClien= new MemcachedClient(memcachedConnectionBuilder.build(),AddrUtil.get(servers));}return this.memcahcedClient;}
2. 就是使用synchronized关键字。
这么做可以保证同步问题,但是我们知道使用synchronized的开销是很大的,会严重影响性能,所以用这个的前提是,你确认不会经常调用这个方法,或者你创建这个instance的开销不会特别大。是否还可以改进,看 下面。
3. 使用“双重检查加锁“,在getInstance中见识使用同步
public Class Singleton{private volatile static Singleton instance;private Singleton(){};public static Singleton getInstance(){ if(instance==null){synchronized (Singleton.class){if(instance==null){instance=new Singleton();}}}return instance;}}
- 一次代码review引发的关于单例模式的思考
- 一次单例模式引发的深思
- 由延时加载的单例模式引发的思考
- 关于装饰模式引发的思考
- 关于单例模式的一些思考
- 关于单例模式的一点思考
- 一次代码Review的总结
- 一次跳槽引发的人力资源思考
- 一次产品讨论会引发的思考
- 一次out of memory引发的思考
- 一次快速排序错误引发的思考
- java单例模式中构造器私有引发的一些思考
- 关于单例模式的DoubleCheckLock同步的思考
- 一段代码引发的思考
- 一段代码引发的思考
- 一段代码,引发的思考。
- 关于C++中实现单例模式的一些思考
- java 关于单例模式的一点思考
- Flex Tree expandChildrenOf 失效的解决办法
- JQuery上传插件Uploadify使用详解
- mysql数据库安装
- Hadoop源代码分析(三)RPC
- Qemu运行错误ACPI.SYS 000000FE
- 一次代码review引发的关于单例模式的思考
- Ubuntu12.04下adb android设备
- Web App安装
- mongodb 随机查询
- Bugzilla安装
- imx53 android patch r10.4 for android 2.3.7_r1
- iOS开发 XCode4 iOS5 改变UINavigationController的UINavigationBar的高度和背景图片 V1
- Python学习笔记(4)-- 网络编程(1)-- socket
- 解决方案"System.InvalidOperationException: 配置有 NoSecurityChanges 标志的 AppDomainManager 修改了 AppDomain 的安全状