单例模式

单例模式

1,基本思想

    确保类在内存中只有一个对象,该类必须自行创建,并且对外提供访问。

2,如何实现

    a,私有构造方法;
    b,自己创建一个私有对象;
    c,提供一个公共方法供外界访问。
本文介绍两种单例设计模式:饿汉式和懒汉式。

3,饿汉式
package com.test.single;
/**
 * 饿汉式
 * @author Administrator
 *
 */
public class Student {
    //1,构造私有
    private Student() {
    }
    //2,自行创建对象
    private static Student s = new Student();
    //3,对外提供访问
    public static Student getInstance() {
        return s;
    }
}
4,懒汉式
package com.test.single;
/**
 * 懒汉式
 * @author Administrator
 *
 */
public class Teacher {
    //1,私有化构造方法
    private Teacher() {
    }
    //2,私有化的对象实例置为null,保证在用的时候才去创建对象
    private static Teacher t = null;
    //3,对外提供访问,注意线程安全问题
    public synchronized static Teacher getInstance() {
        if(t == null) {
            //此处可能有线程安全问题
            t = new Teacher();
        }
        return t;
    }
}
5,两者对比

a,饿汉式是在类加载的时候就创建对象(饿汉是饿了就吃饭);
b,懒汉式是在用的时候才去创建对象(懒汉是不到饿死就不吃饭)。
注意:开发中多用饿汉式,因为饿汉式是不会出问题的单例模式。
    懒汉式的两种思想:
a,懒加载或延迟加载思想;
b,懒汉式的线程安全问题:
    线程安全问题出现的前提:处在多线程环境中,有共享数据,而且有多条语句操作共享数据。
    在懒汉式的情况下:懒汉式例子中的”t”对象就是共享数据,”t == null”和”t = new Teacher();”就是多条语句在操作”t”对象,如果处在多线程环境下,有三个线程thread1,thread2和thread3都进到了” if(t == null){ thread1,thread2,thread3}”中,这时候每个线程都会new一个”t”对象,这就是懒汉式的线程安全问题。

6,双重检查加锁机制

    ”synchronized”解决了懒汉式的线程安全问题,但是这样一来,每次都要在同步的情况下进行判断,浪费时间,也降低了整个访问的速度,所以针对懒汉式的线程安全问题,提出了“双重检查加锁机制”。

package com.test.single;
/**
 * 双重检查加锁机制
 * @author Administrator
 *
 */
public class Singleton {
    //1,私有化构造方法
    private Singleton() {
    }
    //2,volatile修饰的私有化对象
    private volatile static Singleton singleton = null;
    //3,对外提供访问
    public static Singleton getInstance() {
        //先检查实例是否存在,不存在进入同步块,存在就直接返回实例
        if(singleton == null) {
            //同步块,线程安全的创建实例
            synchronized (Singleton.class) {
                //再次检查实例是否存在,不存在才真正的创建实例
                if(singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

    双重检查加锁机制,并不是每次进入”getInstance”方法都需要同步,而是先不同步,进入方法之后先检查实例是否存在,如果不存在才进入下面的同步代码块,这也是第一重检查,如果存在就直接返回实例了。进入同步代码块之后,再次检查实例实例是否存在,如果不存在就在同步的情况下进行实例,这是第二重检查,这样一来就只需要同步一次了,就减少了多次在同步的情况下进行判断所浪费的时间。
    双重检查加锁机制的实现会用到一个关键字”volatile”,它的意思是:被”volatile”修饰的变量的值将不会被本地线程缓存,所有对该变量的读写操作都是直接操作内存,从而确保多个线程能正确的处理该变量。
    这种实现方式即可以实现线程安全,又不会对性能造成太大的影响,它只是在第一次创建实例的时候进行同步,以后就不再需要同步,加快了运行速度。
    注意:
    a,在java1.4及以前的版本中,很多jvm对于”volatile”的实现有问题,会导致双重检查加锁机制失败,因此该机制只能用在java5及以上的版本;
    b,由于”volatile”可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高,因此建议一般没有特别的需要就不要使用。

7,单例优点

    优点:在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式可以大大提高系统的性能;
    缺点:不易扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值