1、由Volatile实现过程,看计算机多核CPU与内存的交互

相关解释:
a、Volatile修饰的变量,会生成Lock前缀的操作指令,Lock前缀指令会引起处理器缓存回写到内存。
b、当CPU 1修改volatile变量,系统内存中值和其他CPU中的缓存失效是即时性的。
c、红色箭头的嗅探操作:嗅探一个处理器来检测其他处理器打算写内存地址,而这个地址当前处于共享状态,那么正在嗅探的处理器将使它的缓存行无效,在下次访问相同内存地址时,强制执行缓存行填充。(类似一个Listener操作)

关键词:
a、内存屏障:上图中当CPU 1修改本地多级缓存并且要写回内存时,会禁止其他CPU操作内存中的值,这个行为被称为内存屏障。
b、MESI协议: 当一个CPU修改了本地中的多级缓存,会通知其他缓存了这个数据的CPU,其他CPU会把Cache中这份数据的Cache Line置为无效,要读取数据的话,直接去内存中获取,不会再从Cache中获取了。

2、Java内存模型(Java Memory Mode, JMM)

思考:
a、我们都知道,java之所以能在多种操作系统中运行,是因为java“自带了”自己的运行容器:JVM。
b、Java又是支持多线程的,多线程操作访问相同的变量,自然也会有类似上面“多核CPU访问操作同一内存地址且要保证缓存一致性的问题”,所以Java也实现了自己的内存模型。

  线程1和线程2都有主内存中共享变量a的副本,初始时,这3个内存中a的值都为0。线程1中更新a的值为1之后同步到线程2主要涉及2个步骤:
  (1)、线程1把线程工作内存中更新过的a的值刷新到主内存中。
  (2)、线程2到主内存中读取线程1之前已更新过的a变量。

  可以看的出来,JMM和计算机多核CPU在处理“高速缓存和内存”的交互上,是非常相似的。

3、JVM内存中的Java对象

思考:为什么Java对象模型没有看到对象方法?

//对象存储的定义
class oopDesc {
  friend class VMStructs;
  friend class JVMCIVMStructs;
 private:
  //重点  mark word 字段
  volatile markWord _mark;
  //重点  Class 字段
  union _metadata {
    // 对象方法就存在了这里,存放的是指针。为何只需要存放一个指针?因为同一个类的不同实例,包含的方法都是一样,为了节省空间,只需要保存相同的指针就可以了
    Klass*      _klass;
    narrowKlass _compressed_klass;
  } _metadata;

  // There may be ordering constraints on the initialization of fields that
  // make use of the C++ copy/assign incorrect.
  NONCOPYABLE(oopDesc);

 public:
  // Must be trivial; see verifying static assert after the class.
  oopDesc() = default;
  }

4、Mark Word,Java对象的状态标识

由上图可以看出Java对象的五种状态:

5、总结与思考:

a、关于对偏向锁的理解
    偏向锁只是逻辑上的锁,是一个概念。偏向锁干的事就是为了保证线程重入的情况下,可以不触发CAS或Mutex锁。由上面的图可以看出,偏向锁记录了“当前线程指针JavaThread”,之所要记录线程指针,是为了判断类似 if(threadId == currentThreadId), 那么跳过获取锁的过程。总结就是:偏向锁是为了线程重入。
b、为什么Mark Word中会用01 来表示无锁的状态 而不是用00表示无锁的状态?
    待补充......
c、class oopDesc中,volatile markWord _mark,是否表示Mark Word是由Volatile实现的?

断水流大师兄
6 声望0 粉丝