基本概念1.可见性当一个线程修改共享变量时,另一个线程可以读取到修改后的值。2.内存屏障(MemoryBarriers)处理器的一组指令,用于实现对内存操作的顺序限制。3.BufferlineCPU告诉cache中可以分配的最小存储单元,当处理器填满cacheline时,它加载整个cacheline。4.Lock前缀的指令Lock前缀的指令在多核处理器下会发生两件事:1)将当前处理器的缓存行的数据关联到系统内存中。2)这种回写内存的操作,会使其他CPU缓存在该内存地址的数据失效。5.缓存一致性协议在多处理器下,零保证每个处理器的缓存是一致的,每个处理器会通过嗅探总线上传播的数据来检查其缓存的值是否过期。当处理器发现自己的缓存行对应的地址被修改时,会将当前处理器的缓存行置为无效状态。当处理器读写这些数据时,它会重新从内存中读取数据到处理器缓存中。6.CASCompareAndSwap比较和交换CAS操作需要输入两个值,一个旧值(执行CAS操作前的值,期望值)和一个新值,只有当当前值等于旧值时,当前值可以设置为新值,否则不设置。这是一个原子操作,由硬件保证。7.重排序规则从根本上是基于JMM对编译器和处理器只有一个重排序限制这一事实。只要程序执行的结果不变(指的是单线程或正确同步的多线程环境),那么编译器和处理器如何优化就可以了。volatile从上面的Lock前缀指令和缓存一致性协议可以看出,这就是volatile的实现原理。其实在写varatile变量的时候,确实是指定了一个Lock前缀来达到可见的目的。finalFinal字段只能显式赋值一次,但这并不意味着final字段不能被多次初始化。例如:finalinti;在构造函数中赋值之前,i会被初始化为默认值:0。这一点可以通过调试代码来证明。为了保证final字段的值在未初始化时不会被访问,程序员只需要保证一件事:即在构造函数中,被构造的对象(this)没有“逃逸”。任何同步方法都需要确保任何线程看到的final字段,包括基本类型和引用类型,都已经通过构造函数正确初始化。正在构造的对象逃逸的例子:publicclassFinalTest{finalinti;staticFinalTestobj;publicFinalTest(){i=1;/***这会导致正在构造的对象逃逸,如果从上一句重新排序,那么其他线程可以通过obj访问未初始化的final字段。**/obj=this;}}Happens-Before规则happens-before的含义Happen-Before规则用于描述两个操作之间的顺序关系。这两个操作可以在一个线程中,也可以不在一个线程中。里面。这个顺序并不是严格意义上的执行时间顺序,而是前一个操作的结果应该对下一个操作可见。Happens-Before关系的定义如下:如果一个happens-before另一个操作,那么第一个操作的执行结果对第二个操作可见,并且第一个操作的执行顺序是在第二个操作之前两次操作之间存在happens-before关系并不意味着Java平台的具体实现必须按照happens-before关系规定的顺序执行。如果重排后的执行结果与happens-before关系下的执行结果一致,则本次重排不违法。比如A在程序执行顺序上先于B,A修改了共享变量,而B刚好使用了共享变量,那么A需要happen-beforeB。当B修改时需要B可见执行它。happens-beforerule程序顺序规则:一个线程中的每一个操作,happens-before该线程中的任何后续操作。监控锁规则:解锁一个锁,happens-before在后续锁的加锁中。易失性规则:对易失性域的写入发生在对易失性域的任何后续读取之前。传递性:如果Ahappens-beforeB,且Bhappens-beforeC,则Ahappens-beforeC。start()规则:如果线程A执行操作ThreadB.start(),则线程的ThreadB.start()操作Ahappens-before线程B中的任何操作。join()规则:如果线程A执行操作ThreadB.join()并成功返回,则线程B的任何操作happens-before线程A从ThreadB.join()操作成功返回。所有这些规则的解释:Ahappens-beforeB并不是说A一定发生在B之前,而是说如果A已经发生在B之前,那么A的运算结果必须对B可见
