深入理解共享模型之内存

4.共享模型之内存

  1. Java内存模型JMM(Java Memory Model),它定义了主存、工作内存等抽象概念。底层对应着cpu寄存器、缓存、硬件内存、cpu指令优化等。
    JMM体现在:原子性:保证指令不会受到线程上下文切换的影响。
    可见性:保证指令不会受到cpu缓存的影响
    有序性:保证指令不会受cpu执行并行优化的影响

  2. 可见性问题原因:1.初始状态,线程刚开始从主内存读取了变量的值到工作内存 2.因为线程要频繁从主内存中读取变量的值,JIT编译期会将变量的值缓存到自己工作内存的高速缓存中,减少对主存中变量的访问,提交效率
    3.当别的线程修改了变量的值并同步到主存后,该线程仍然是从高速缓存中读取值,所以永远是旧值。
    解决方法:volatile(易变关键字),它可以用来修饰成员变量和静态成员变量,可以避免线程从自己的工作缓存中查找变量的值,而必须到主存中,线程操作volatile变量都是直接操作主存。
    PS:给对象加锁也可以,但是要创建Monitor锁,比较重量级,synchronized既可以保证可见性,也可以原子性
    volatile只能保证看到最新值(可见性),不能解决指令交错(原子性)

  3. 多线程下指令重排会影响正确性,即调整语句的执行顺序。
    现代cpu支持多级指令流水线,例如同时支持取指令-指令译码-执行指令-内存访问-数据写回的处理器,就可以称之为五级指令流水线,这时cpu可以在一个时钟周期内,同时运行五条指令的不同阶段。本质上,流水线技术并不能缩短单条指令的执行时间,但它变相地提高了指令的吞吐率。

  4. volatile的底层实现原理是内存屏障。保证可见性:写指令后会加入写屏障,读指令前会加入读屏障。
    写屏障保证在该屏障之前的操作,对共享变量的改动,都同步到主存当中。
    读屏障保证在该屏障之后的操作,对共享变量的读取,加载的是主存中的最新数据
    保证有序性:写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
    读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前
    但不能保证原子性:不能解决指令交错,有序性只是保证了本线程内相关代码不被重排序,但多线程之间的原子 性无法保证
    更底层是读写变量时使用lock指令来保证多核cpu之间的可见性和有序性

  5. happens-before:规定对共享变量的写操作对其他线程的读操作可见,它是可见性和有序性的一套规则总结。
    m代表锁,x代表变量
    1.线程解锁m之前对x的写,对接下来对m加锁的其他线程对x的读可见、
    2.线程对volatile变量的写,对接下来其他线程对x的读可见
    3.线程start之前对x的写,对该线程开始后对x的值的读可见
    4.线程结束前对x的写,对其他线程得知它结束后的读可见(其他线程调用isAlive()或join()等方法等它结束)
    5.线程t1打断t2前对x的写,对于其他线程得知t2被打断后对x的读可见
    6.对变量默认值(0,false,null)的写,对其他线程对x的读可见
    7.具有传递性,如果x hb->y并且y hb-> ,那么x->z

  6. 线程安全单例习题:
    1.为什么加final:防止子类不适当地覆盖了父类中的一些方法,破坏了单例
    2.如果实现了序列化接口,还要做什么来防止反序列化破坏单例?
    反序列化也可以生产对象,跟单例模式生成的对象不是同一个,这时可以在类中加入以下方法返回单列对象
    public Object readResolve(){
    return INSTANCE;
    }
    3.为什么设置为private,能否防止反射创建新的实例? 防止其他的类创建创建对象。
    不能,因为反射可以得到构造器对象,可以设置构造器对象的setAccessible,暴力调用构造方法创建实例
    4.private static final Singleton INSTANCE = new Singleton();这样初始化能否保住线程安全?
    可以,静态成员变量是在类加载的时候由jvm创建
    5.为什么提供静态方法,而不是直接将INSTANCE设置为public?
    可以提高对象的封装性,内部实现一些懒惰的初始化,创建单例对象时有更多的控制,提供泛型的支持

  7. 枚举单例:
    1.枚举单例是如何限制实例个数的?
    枚举类里定义的枚举对象定义时有几个将来就有几个,相当于是静态成员变量,是单实例的
    2.枚举单例在创建时是否有并发问题 没有,也是在类加载的时候完成的
    3.枚举单例能否被反射破坏单例? 不能
    4.枚举单例能否被反序列化破坏单例? 枚举类默认实现了序列化接口,但系统已经做了处理
    6.枚举单例属于懒汉式还是饿汉式? 饿汉式
    7.枚举单例如果希望加入一些单例创建时的逻辑化接口该怎么做? 写一个构造方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值