设计模式学习笔记——单例模式

应用场景

用来管理共享的资源,例如数据库连接或者线程池,在全局仅有一个实例。

定义

单例模式确保一个类只有一个实例,并提供一个全局访问点。

延迟实例化(懒汉式)

懒汉式,顾名思义就是比较懒,不用的时候不实例化,用到它的时候再实例化,这对资源敏感的对象特别重要。

public class LazyBoy{
    private static LazyBoy instance;
    private LazyBoy(){
        //资源加载等
    }
    public static void getInstance(){
        if(instance == null){
            instance = new LazyBoy();   
        }
        return instance;
    }
}

我们可以发现,懒汉式单例模式拥有一个静态的单例类的变量,一个私有的构造函数,一个静态的获取单例对象的方法,这基本上是懒汉式的标配。

懒汉式的问题所在

当我们使用多线程时,会发生如下所示的情况:
这里写图片描述
当进行多线程操作时,当Thread1运行到if(instance==null)时,即将运行下一行,由于CPU的并发性,该线程时间片用完阻塞,轮到Thread2执行,并执行到if(instance==null),发现是true
此时,会有两个线程进入到实例化代码块,这样会造成两个不同的实例对象,这就是所谓的非“线程安全”。

处理多线程

1、同步的方法

第一种方法就是使用同步的方法:

public class LazyBoy{
    private static LazyBoy instance;
    private LazyBoy(){
        //加载资源
    }
    public static synchronized LazyBoy getInstance(){
        if(instance == null){
            instance = new LazyBoy();
        }
        return instance;
    }
}

这里使用了同步的方法(synchronized),但是使用synchronized 会大大降低执行的性能。

2、双重检查锁

第二种是使用双重检查锁的方法:

public class LazyBoy{
    private volatile static LazyBoy instance;
    private LazyBoy(){
        //加载资源
    }
    public static LazyBoy getInstance(){
        if(instance == null){
            synchronized(LazyBoy.class){
                if(instance == null){
                    instance = new LazyBoy();
                }
            }
        }
        return instance;
    }
}

使用了volatile类型修饰符,该修饰词只能让该变量尽快的变化,通知线程该变量发生变化,但不能保证原子性。
volatile类型修饰符,参考:http://www.importnew.com/24082.html

3、饿汉式

由于上面懒汉式是非线程安全的,通常情况下又会进行多线程优化。现在提出一种程序初始化时,就进行实例化的方案,称为饿汉式单例模式。
代码模式如下:

public class DiligentBoy(){
    public static DiligentBoy instance = new DeligentBoy();
    private DiligentBoy(){
        //资源初始化
    }
    public DilegentBoy getInstance(){
        return instance;
    }
}

在静态初始化器中创建单例。在初始化时实例化了变量,这保证了线程安全。

猜你喜欢

转载自blog.csdn.net/u012525096/article/details/79768554
今日推荐