线程——单例模式

首先我们要了解单例模式,那么什么是单例模式
单例模式:如果一个类在程序中值存在一个实例 通过一定的编程手段来进行限制,防止不小心在代码中创建了多个实例
单例模式的实现有二种方式一种是饿汉模式另一种是懒汉模式 下面我介绍给大家
饿汉方式
饿汉方式顾名思义就是饿了的人吃饭,只要是能吃的都会直接吃 ,这里对应到代码就是不管这个对象能不能用到先创建了这个对象在说 下面是代码的实现

     //Singleton 单例
    static class Singleton{
        //1.创建一个私有的静态本类对象
        private static Singleton instance = new Singleton();
        //当把这个类的构造方法设置为私有的时候,此时这个类就无法在类外部被实例化了
        //2.创建一个私有的构造方法
        private Singleton() {
        }
        //3.提供一个可以访问到该类的方法
        public static Singleton getInstance() {
            return instance ;
        }
    }

getInstance 得到的类内部的静态成员
静态成员是和类相关的(在类对象中),每个类只有一个类对象
此时调用getInstance 得到的实例其实是同一个对象
只要类一被加载就会进行实例化 就会给对象分配内存
懒汉方式
当类加载的时候,不会创建实例,直到第一次使用这个实例了再创建

 //当程序吧类加载的时候,并没有第一次申请内存空间
        //1.先声明一个静态的私有的Singleton对象 ,不创建,当第一次使用的时候才开始实例化对象
        private static Singleton instance = null;
        //2.构建一个私有的构造方法,是外部无法直接实例化对象
        private Singleton (){

        }
        //3.给外部提供一个获取对象的方法,当一次一使用的时候开始实例化对象
        public static Singleton getInstance() {
            if (instance==null) {
                instance = new Singleton();
            }
            return instance;
        }

要比饿汉模式 更加常用 效率高
如果这个对象没有被使用那么,也就不会被涉及到内存分配,也就节省了不必要开销
饿汉模式中不管是否用到这个实例,都会分配内存(分配内存操作可能会分配很大的内存,非常消耗时间)

那么在多线程编程的时候单例模型是否安全的,如果不安全应该如何来改进
饿汉模式
实例的创建是在Singleton 类被加载的时候进行的,类被加载的时机只有一次(JVM内部控制的)此时就和多线程无关了
如果多个线程调用getInstance,此时不涉及到多线程同时修改通一个变量,此时也不会有安全问题

懒汉模式
当多个线程同时调用getInstance的时候,有可能会多个线程同时修改,也就存在线程安全问题
本质上还是多个线程修改同一个变量进行修改 并且修改的变量不是原子的
修改操作分为好几步
1.获取instance的值
2先判定instance非空
3.非空就new对象
4.把new得到的结果写回到instance
当instance 为空时 因为是抢占式执行 ,所以会很多的同时获取到instance 为空时 就会创建很多个对象
存在线程安全问题

那么我们应该怎么样去解决线程安全问题呢?
没错还是加锁。下面就是懒汉模式的进阶版本

 static class Singleton {
        private static Singleton instance = null ;
        private Singleton () {

        }
        public Singleton getInstance() {
            if (instance==null) {
                synchronized (Singleton.class) {
                    if (instance==null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

当实例被创建之前,多线程调用getInstance ,就会进入第一个if,从而触发锁操作,这个锁操作就能保证线程安全,获取锁完毕之后,第二个if 就能保证最终的new值执行一次
如果实例已经被创建之后,多线程调用getInstance,第一个if进不去,也就不会触发锁操作(提升了性能,此时也没有线程安全问题),直接返回instance ,也避免了不必要的锁开销

那么这个版本的懒汉模式是否就是线程安全的呢?
不一定,当第一个线程获取到锁的时候,其他线程就会快速读取instance的值,编译器可能会进行优化,第二次读到的内容不一定是从内存中重新读取的,也可能直接使用第一次读到的结果。
所以它会再去new一个对象,也就不符合单例模式了
那么怎么解决尼 ,可以使用volatile关键字 代码如下

 static class Singleton {
        private volatile static Singleton instance = null ;
        private Singleton () {

        }
        public Singleton getInstance() {
            if (instance==null) {
                synchronized (Singleton.class) {
                    if (instance==null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值