单例模式的实现
程序员文章站
2022-07-13 23:46:16
...
单例模式指的是在应用整个生命周期内只能存在一个实例
实现单例模式
一、饿汉式
- 以空间换时间的方式
- 在定义类的静态私有变量同时进行实例化
优点:线程安全;获取实例速度快
缺点:类加载即初始化实例,内存浪费
public class Singleton {
private static Singleton instance=new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return instance;
}
}
二、懒汉式-----线程安全
- 以时间换空间的方式
- 等到用着的时候才去实例化
在多线程并发的环境下可能出现资源同步问题
懒汉式在单个线程中没有问题,但多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象,虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大
public class Singleton {
private static Singleton instance;
private Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
/*
*懒汉式---线程不安全 (区别 -->synchronized )
public static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
*/
}
优点:
- 在获取实例的方法中,进行实例的初始化,节省系统资源
缺点:
- 如果获取实例时,初始化工作较多,加载速度会变慢,影响系统系能
- 每次获取实例都要进行非空检查,系统开销大
- 非线程安全,当多个线程同时访问getInstance()时,可能会产生多个实例
三、双重校验锁
public class Singleton {
private static volatile Singleton instance;
private Singleton(){
}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
问题根源:instance= new Singleton();
可以分解为下面三段代码:
memory=allocate(); //1、分配对象的内存空间
ctorInstance(memory); //2、初始化对象
instance=memory; //3、设置instance指向刚分配的内存地址
在一些编译器上可能会被重排序,如下:
memory=allocate(); //1、分配对象的内存空间
instance=memory; //3、设置instance指向刚分配的内存地址
ctorInstance(memory); //2、初始化对象
先分配了内存指向,会导致另一个线程访问一个还未初始化的对象。所以使用volatile关键字,不允许重排序。
优点:线程安全,进行双重检查,保证只在实例未初始化前进行同步,效率高
缺点:实例非空判断,耗费一定资源
四、静态内部类
public class Singleton {
private Singleton(){
}
private static class SingletonHolder{
private static Singleton instance=new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
优点:既避免了同步带来的性能损耗,又能够延迟加载
单例模式的优缺点
优点:该类只存在一个实例,节省系统资源;对于需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
缺点:不能外部实例化(new)。
上一篇: java web验证码相关
下一篇: C++ 单例模式讲解和代码示例