当前位置:编程学习 > JAVA >>

浅谈单例模式

单例模式在很多场景下都有应用,例如数据库连接池,日志,等。当系统对于某一个类只需要一个实例的时候,如果能产生两个或更多实例只会带来麻烦和错误,好比两个程序如果操作的不是同一块内存,那么两个程序所有的操作也不会达成一致,或者在同步的过程就会出错。
所谓单例模式,我觉得从内存角度来看,就是多个线程共享一块内存,而这块内存就只是一个类的实例。而使用单例模式最简单的方式就是饿汉式单例模式:
[java]  
public class Single{  
    private static Single current = new Single();  
    public static Single getSingle(){  
         return current;  
    }  
    private Single(){}  
}  
 
关键点有两个:
1.在单例模式中,需要将构造函数定义为private,因为这样可以防止通过构造函数获取更多的实例。
2.需要将唯一的实例定义为static类型的成员变量,否则无法直接通过类获取单例。
 
为什么称之为饿汉单例模式,我的理解是当还不需要唯一的单例的时候就已经将这个单例创建出来了,好比还不饿的时候就已经将饭做好了一样,所以称之为饿汉单例模式,只要“饿了”立即可以拿来“吃”,不然等到饿了的时候才去做饭,估计就要饿死了吧。
饿汉单例模式的优点在于:需要单例的时候相应速度快,无需在需要的时候创建,在类创建的时候就已经有了一个实例,代码更容易编写。缺点在于:让类的加载速度变慢,影响系统响应时间(运行初期就要先new一个实例出来),浪费资源(还没使用这个单例的时候就得将其放置于内存中)。
下面看饿汉单例模式的改进,也即:饱汉单例模式:
[java] 
public static Single{  
    private static Single current = null;  
    private Single(){}  
    public static Single getInstance(){  
        if(current == null){  
            current = new Single();  
        }  
        return current;  
    }  
}  
 
这段代码在单线程的情况下是没有问题的,如果有多个线程都在访问getInstance方法,就会出现问题。多个线程先后判断current为null是true,然后交错执行current = new Single(),这样就产生了多个实例。改进的方式如下,加入同步机制:
[java]  
public class Single {  
    private static Single current = null;  
    private Single(){}  
    public static synchronized Single getInstance(){  
        if(current == null){  
            current = new Single();  
        }  
        return current;  
    }  
}  
这种方式虽然可以达到要求,但是非常影响性能,无论current是否已经创建,每一次获取这个current都会进入synchronized机制,而current不是null的情况下应该直接将current返回才对,而不应该进入同步机制。所以改进如下:
[java] 
public class Single {  
    private static Single current = null;  
    private Single(){}  
    public static Single getInstance(){  
        if(current == null){  
            synchronized(Single.class){  
                current = new Single();  
            }  
        }  
        return current;  
    }  
}  
但是这种写法也存在问题:多线程同时进入if(instance == null)的判定,然后又创建多个实例。所以此时需要Double-checked locking(双检测锁)机制,如下:
[java] 
public class Single {  
    private static Single current = null;  
    private Single(){}  
    public static Single getInstance(){  
        if(current == null){  
            synchronized(Single.class){  
                if(current == null){  
                    current = new Single();  
                }  
            }  
        }  
        return current;  
    }  
}  
 
这样一来,就完成了单例模式的设计,首先提出了最简单的饿汉式单例模式,然后考虑到可以优化就引入了饱汉式单例模式,饱汉式单例模式的进化过程:多线程并发导致多实例的问题,同步时的性能问题,然后又出现了多线程并发导致多实例的问题,最后利用Double-checked locking解决。
 
补充:软件开发 , Java ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,