单例模式
2015-09-14 15:18
344 查看
对于单例模式探讨,网上的大牛,都给了很多不同视角的解释。本篇博客,仅仅是对他们观点的一个总结。
下面我将分三步,来一起学习一下单利模式。
(1)它要解决一个什么问题:
对于这个问题的理解,由于自己的经验原因,认识的并不深刻,从别人的观点来看,它是为了解决不一致的状态。(这个在实际工作当中遇到后,再修改本文)
(2)它有什么特点:
1.自己创建自己的实例
2.类只能被实例化一次,实例唯一.
3.可以被其他所有类调用
(3)它是如何实现的:
1.最简单的实现
先不考虑,线程安全,性能,我们来写一个最基本的单例模式的类
(饿汉单例)
public class Singleton{
private static final Singleton singleton=new Singleton();
public static Singleton getSingleton(){
return singleton;
}
}
2.性能的优化
这段代码可以简单的创建一个实例,也就是在JVM加载上述类的时候,就会创建一个Singleton实例,也就是不管我们用不用它,它自己就会创建自己,这样的类如果数量少还好,当有很多的时候,就会占用资源.
既然是它是自动的创建,那我们手动创建不就好了吗?!
为此我们可以简单的修改以上代码
(懒汉单例)
public class Singleton{
private static Singleton singleton=null;
public static Singleton getSingleton(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
3.线程同步
上面这段代码我们可以在单线程的情况下简单,便捷的创建一个Singleton实例,但是当在多线程的条件下,上边的创建方式就会出现问题。
我们来分析一下多线程可能出现的问题的原因.现在有线程A和线程B两个线程,当A执行以上代码判断singleton为null,就在此时cup时间片切换,b线程也执行到这一块,此时对于线程A它并没有实例化,所以b线程此时也会判断它为null进而实例化singleton,这时候问题就出现了,A线程B线程都会实例化Singleton,有两个singleton存在.(当然,这里还有很多问题需要考虑,程序的原子性,可见性.但是为了简化问题,我们不做探究,以后再做修改),
为了解决线程同步问题,我们可以给方法加一个锁.
public class Singleton{
private static Singleton singleton=null;
public static Singleton getSingleton(){
synchronize(Singleton.class)
{
if(singleton==null){
singleton=new Singleton();
}
}
return singleton;
}
}
4.性能
上面的代码成功的解决了线程同步的问题(还有其他方式),但是问题又来了,要知道synchronize是很消耗资源的,我们每次获取Singleton实例的时候,都会synchronize
。可见这样并不是一个很好的方式,我们回想一下刚才开始时,我们也需要到了优化性能的问题,避免自动Singleton自动实例化,我们加入if判断手动的进行实例化,因此我们也可以这样修改先判断是否已经实例化,再进行线程同步
public class Singelton{
public static Singleton singleton=null;
public static Singleton getSingleton(){
if(singleton==null){
synchronize(Singleton.class){
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}
}
5.总结
单例模式简单的说可以分为两种,也就是上边懒汉单例,饿汉单例,饿汉单例因为在加载的时候实例化Singleton对象,所以天然的线程安全,懒汉单例的线程是不安全的,所以上面我们也讨论了一下解决办法。
当然关于单例模式还有一些 比如 通过静态内部类:
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗。(以上引述
) 对于这种机制 不是特别熟悉 以后再做
下面我将分三步,来一起学习一下单利模式。
(1)它要解决一个什么问题:
对于这个问题的理解,由于自己的经验原因,认识的并不深刻,从别人的观点来看,它是为了解决不一致的状态。(这个在实际工作当中遇到后,再修改本文)
(2)它有什么特点:
1.自己创建自己的实例
2.类只能被实例化一次,实例唯一.
3.可以被其他所有类调用
(3)它是如何实现的:
1.最简单的实现
先不考虑,线程安全,性能,我们来写一个最基本的单例模式的类
(饿汉单例)
public class Singleton{
private static final Singleton singleton=new Singleton();
public static Singleton getSingleton(){
return singleton;
}
}
2.性能的优化
这段代码可以简单的创建一个实例,也就是在JVM加载上述类的时候,就会创建一个Singleton实例,也就是不管我们用不用它,它自己就会创建自己,这样的类如果数量少还好,当有很多的时候,就会占用资源.
既然是它是自动的创建,那我们手动创建不就好了吗?!
为此我们可以简单的修改以上代码
(懒汉单例)
public class Singleton{
private static Singleton singleton=null;
public static Singleton getSingleton(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
3.线程同步
上面这段代码我们可以在单线程的情况下简单,便捷的创建一个Singleton实例,但是当在多线程的条件下,上边的创建方式就会出现问题。
我们来分析一下多线程可能出现的问题的原因.现在有线程A和线程B两个线程,当A执行以上代码判断singleton为null,就在此时cup时间片切换,b线程也执行到这一块,此时对于线程A它并没有实例化,所以b线程此时也会判断它为null进而实例化singleton,这时候问题就出现了,A线程B线程都会实例化Singleton,有两个singleton存在.(当然,这里还有很多问题需要考虑,程序的原子性,可见性.但是为了简化问题,我们不做探究,以后再做修改),
为了解决线程同步问题,我们可以给方法加一个锁.
public class Singleton{
private static Singleton singleton=null;
public static Singleton getSingleton(){
synchronize(Singleton.class)
{
if(singleton==null){
singleton=new Singleton();
}
}
return singleton;
}
}
4.性能
上面的代码成功的解决了线程同步的问题(还有其他方式),但是问题又来了,要知道synchronize是很消耗资源的,我们每次获取Singleton实例的时候,都会synchronize
。可见这样并不是一个很好的方式,我们回想一下刚才开始时,我们也需要到了优化性能的问题,避免自动Singleton自动实例化,我们加入if判断手动的进行实例化,因此我们也可以这样修改先判断是否已经实例化,再进行线程同步
public class Singelton{
public static Singleton singleton=null;
public static Singleton getSingleton(){
if(singleton==null){
synchronize(Singleton.class){
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}
}
5.总结
单例模式简单的说可以分为两种,也就是上边懒汉单例,饿汉单例,饿汉单例因为在加载的时候实例化Singleton对象,所以天然的线程安全,懒汉单例的线程是不安全的,所以上面我们也讨论了一下解决办法。
当然关于单例模式还有一些 比如 通过静态内部类:
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗。(以上引述
一个本科小生的奋斗史
) 对于这种机制 不是特别熟悉 以后再做
相关文章推荐
- 关于字符串的一些讨论
- Enhacing the content with JavaScript
- hdu5044 Tree 树链拆分,点细分,刚,非递归版本
- 正则表达式字符说明
- [LeetCode]题解(python):010-Regular Expression Matching
- UIGestureRecognizer手势
- Zabbix discovery disk 监控
- HDOJ1003.Max Sum
- cocos2d-x 集成社交分享平台shareSDK
- java.lang.NoClassDefFoundError: org/apache/log4j/Layout
- 装饰图案 C#
- 前端性能优化的总结
- 用yum查询想安装的软件
- 通过Socket实现UDP(用户数据报)编程
- c# lua 简单交互
- C语言字符串反转实现【采用头指针和尾指针方法完成】
- excel2003 操作
- android中svg文件的使用
- 产品管理?企业规范化?iclap秀出新高度
- ActionBar SearchView空指针异常