设计模式——单例模式

  • 定义
一个类只能有一个实例
  • 应用
线程池、日志对象、缓存等。需要让这些对象在整个程序中只有唯一的实例,
保证所有访问它们的对象得到的都是同样的数据。
  • 单例模式的关键
1.私有化构造方法
2.提供公共的构造方法返回单实例,供其他对象访问
3.声明一个变量保存实例化出来的单实例
  • 懒汉式单例模式(斗王级别)
//懒汉式
public class LazySingleton {

    //懒汉式,开始不实例化,等到用的时候再实例化
    //保存唯一单实例
    private static LazySingleton singleton ;

    //私有构造
    private LazySingleton(){}

    //提供公共访问点(声明成静态方法,直接使用类调用)
    public static LazySingleton getSingletonInstance(){
        if(singleton == null){
            singleton = new LazySingleton();
        }
        return singleton;
    }

    //问题
    //这种单例模式在多线程环境下依然无法保证只存在一个实例
    //假如:有两个线程,线程1和线程2同时执行LazySingleton.getSingletonInstance(),(此时该类还未被实例化过)
    //如果线程1的singleton = new LazySingleton();语句还没执行完,这时线程2执行if(singleton == null)依然返回true
    //那么线程2也将new一个实例,最终线程1和线程2都实例化了一个对象。完全违背了单例模式
}
  • 懒汉式单例模式(斗皇级别)
//为了解决最开始的懒汉式在多线程环境中的问题,需要对getSingletonInstance进行同步
public class LazySingleton2 {

    //保存唯一单实例
    private static LazySingleton2 singleton ;

    //私有构造
    private LazySingleton2(){}

    //提供公共访问点(声明成静态方法,直接使用类调用)

    //加上同步,保证多个线程只有一个可以进入该语句块,那么其他线程再进入时,实例已经被创建,if(singleton == null)返回false
    public static synchronized LazySingleton2 getSingletonInstance(){
        if(singleton == null){
            singleton = new LazySingleton2();
        }
        return singleton;
    }

    //问题
    //虽然加了同步块之后解决了懒汉式单例模式在多线程环境中的问题,但是由于同步的原因,使用代码的性能大大降低
    //而且,只需要在第一次实例化该类时才需要同步,一旦实例化后,后续if(singleton == null)永远返回false,就不需要同步
}
  • 懒汉式单例模式(斗宗级别)
//双重检验加锁
//加了同步之后使得懒汉式单例模式性能大大降低,需要再次修改
public class LazySingleton3 {

    //保存唯一单实例
    //volatile可以保证多个线程在使用singleton时,可以保证数据的一致性
    private volatile static LazySingleton3 singleton ;//volatile不支持java1.4之前的版本

    //私有构造
    private LazySingleton3(){}

    //提供公共访问点(声明成静态方法,直接使用类调用)

    //不是直接同步,而是先进行判断,只有第一次实例化该类的时候加锁
    //那么只要实例化后,后续的线程进来,由于if(singleton == null)返回false,将不会进入同步,提升了性能
    public static synchronized LazySingleton3 getSingletonInstance(){
        if(singleton == null){
            synchronized (LazySingleton3.class) {
                if(singleton == null) {
                    singleton = new LazySingleton3();
                }
            }
        }
        return singleton;
    }
}
  • 饿汉式单例模式
//饿汉式
public class HungrySingleton {

    //饿汉式,一开始就实例化
    //保存唯一单实例
    private static HungrySingleton singleton = new HungrySingleton();

    //私有构造
    private HungrySingleton(){}

    //提供公共访问点(声明成静态方法,直接使用类调用)
    public static HungrySingleton getSingletonInstance(){
        return singleton;
    }
    //饿汉式,getSingletonInstance方法中只存在一条语句,不会引发多线程问题
}
  • 测试未同步的懒汉式
//实现Runnable接口,编写多线程
public class ThreadLazySingleton implements Runnable{

    @Override
    public void run() {

        String name = Thread.currentThread().getName();
        LazySingleton lazy = LazySingleton.getSingletonInstance();

        System.out.println("线程" + name + "得到实例" + lazy);
    }
}
//测试代码
public class testSingletonDemo {
    public static void main(String[] args) {

        Thread t1= new Thread(new ThreadLazySingleton(),"线程1");
        Thread t2= new Thread(new ThreadLazySingleton(),"线程2");
        Thread t3= new Thread(new ThreadLazySingleton(),"线程3");

        t1.start();
        t2.start();
        t3.start();

    }
}
  • 结果
结果(1)
	线程线程1得到实例pattern.singleton.LazySingleton@5c562746
	线程线程3得到实例pattern.singleton.LazySingleton@5c562746
	线程线程2得到实例pattern.singleton.LazySingleton@5c562746
结果(2)
	线程线程1得到实例pattern.singleton.LazySingleton@3133744f
	线程线程3得到实例pattern.singleton.LazySingleton@273bdf75
	线程线程2得到实例pattern.singleton.LazySingleton@25d849fd
结果(3)
	线程线程2得到实例pattern.singleton.LazySingleton@2839e23b
	线程线程3得到实例pattern.singleton.LazySingleton@2839e23b
	线程线程1得到实例pattern.singleton.LazySingleton@2839e23b
  • 从结果看出,没被同步的懒汉式,在多线程环境下,会出现多个线程得到了不同的实例的情况。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值