• 大豆
    2021-12-08
    1、volatile不能代替锁,它的作用是绕过高速缓存,直接与内存进行交互并读写数据。 2、当多线程时,会存在线程A将新值写入内存前,线程B又从内存读取了旧值,这样就会导致sum的值不会是80000。 3、要想sum的值为80000,还得给Main.sum += 1;这句代码加锁。 4、volatile还有一个作用是防止指令重排,对吗?老师。

    作者回复: 太对了,同学!

    共 6 条评论
    5
  • AriseFX
    2022-02-16
    请教一个问题,思考题如果使用CAS来更新sum的话,这里使用volatile关键字还有意义么,CAS不是已经包含了volatile读/写的语义么?

    作者回复: 使用cas,就不用再使用volatile了,cas确实会保证可见性。

    共 5 条评论
    1
  • 王建新
    2021-12-15
    菜鸡求请教:acquire 语意,和release 语意 都代表什么,求解答。。

    作者回复: 第15课里有的,volatile之所以难就是需要的前置知识多。要耐心点从头看。

    
    1
  • 送过快递的码农
    2021-12-09
    我尝试对之前的知识和今天的文章我来梳理一下。volatile 关键字修饰的变量要遵循happen-bofore模型。由于cpu缓存的情况,我们会出现读滞后数据的情况。前面的知识,cpu通过缓存一致性协议,对缓存状态进行管理,一旦失效,会通过总线同步给其他核心。但是由于,这样性能成本太高,所以出现写缓存区+失效队列+内存屏障来进行补充?又由于我理解这个是jmm内存模型提出的规范,由于不同平台,不同cpu缓存架构不一样,cpu所提供的内存屏障实现也不一样。volatile关键字,虽说是可见性,但是也是集cpu,操作系统,jvm这些在不同层级上做自己的事情,方能实现。感觉也是现代计算机知识体系的一个精华(由于,前面很多看了不懂不懂,所以麻烦老师看看我的理解对不对,感觉这个也是要多刷的,不然越学越废)

    作者回复: 我觉得你这个总结还是感性上的一种总结,还不够精细。大体方向是对的。但细节还要再多抠一下。

    共 2 条评论
    
  • raisecomer
    2021-12-08
    “happen-before模型”的表格中“对volatile的写操作在对该变量的读操作之前执行”,太令人费解了

    作者回复: 这就是jsr133文档难受的地方,我这里是照着翻译回来的。其实他想说的是写操作如果在程序里出现在读操作之前,那就不能乱序。这就是写后读屏障的规则。其实你不用太在意jsr133说的是什么,只要看Doug lea给的那张表就行了。

    共 2 条评论
    
  • .
    2021-12-08
    volatile作用的自我总结: 1.给编译器看在编译层面禁止重拍 2.给虚拟机看让其在对应的指令加入屏障。防止cpu级别的重排序与缓存一致性问题 思考题: 这个问题就像++i问题类似,由于加一是由多个字节码才能完成(java虚拟机基于栈的设计尤其明显比安卓虚拟机完成一件事需要更多指令)。假设cpu1取出数据放入操作栈,还没进行计算操作,而此时时间片正好用完另线程cpu2完成一次加一,在切回cpu1时数据已经错误。 解决方案: 1.加锁保证多线程的串行 2.操作变成原子操作,如使用并发包下的原子类 老师能不能以后讲讲cpu之上的内存模型呢?比如arm

    作者回复: 总结得非常好!15,16课已经讲过了啊,arm上就是采用了dmb, arquire, release这三种。

    
    
  • 李二木
    2021-12-08
    volatile 只能保证可见性和有序性。不能保证原子性。

    作者回复: Bingo~

    
    
  • anqi
    2022-05-30
    volatile 可以保证可见性,但无法保证原子性 因为数据可能在 寄存器或者 (store buffer + cpu cache + memory)组成的内存子系统中, 当在寄存器中时,如果发生中断,另一个线程仍然可以在上面的内存子系统中读到同样的值, 造成两次操作都是基于一个值做了自增操作,虽然刷新回内存的操作可以保证可见性,但已经于事无补了。
    
    2
  • AriseFX
    2022-02-16
    思考题 public void run() { long sumOffset = UNSAFE.staticFieldOffset(Main.class.getDeclaredField("sum")); for (int i = 0; i < 40000; i++) { UNSAFE.getAndAddInt(Main.class, sumOffset, 1); } }
    
    1
  • 卖藥郎
    2022-03-31
    volatile 能替代锁(或者 CAS 操作)的能力吗? 答:不能。比如 i++,实际会包含读改写三个操作,T1从主存中读取值之后,由于没有原子性限制,主存中的值可能会在此刻发生变化。 不知道这样理解的对不对,望老师指正
    
    