锁升级的过程;CAS;对象内存布局问题;object在内存中占几个字节;

一.CAS是什么?

  1. CAS(Compare and swap)比较与交换, 是一种有名的无锁算法,CAS的3个操作数:内存值V,旧的预期值A,要修改的新值B
  2. CAS可保证在无锁的状况下,多给线程对一个值的更新
  3. 当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值(A和内存值V相同时,将内存值V修改为B),而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试(否则什么都不做)
    经典ABA问题:当读取到的内存值V是被修改过(只是1变为2又变为1)这种情况,需要在每次计算后的值上,加版本号,来标识。或者使用boolea类型的值来标识。

二.CAS,volatile,sychronized的底层实现原理:
他们的原理有一样-----lock cmpxchg指令(hotspot层级,native修饰的)

三.一个object对象在内存中占多少字节呢
对象内存布局问题
普通对象在内存中由四部分组成:对象头(markword);类型指针(class pointer);实例数据(instance data);对齐(padding)。

  1. markword:【占8个字节】主要存的是关于sycnroniazed锁信息,和GC信息
  2. classpointer:【压缩后占4个字节(一般);没压缩是8个字节】表示这个对象属于哪个类
  3. instance data:【看具体数据类型】比如m = new A(); 是int类型的,占4个字节
  4. padding:【对齐】这四个字节数加起来必须可以整除8.不行的话由padding补齐(因为sychronized读内存的值得时候,按总线宽度来读,被8整除时读的快,效率高。)
    (1)在classpointer被压缩的情况下:object对象 1和2为8+4=12个字节。他没有实例的话3=0字节;12不能整除8,所以补齐16.所以object对象在内存中占16个字节。
    (2)在classpointer不被压缩时:1和2为8+8=16个字节,3为0,此时正好可以整除8。所以这个情况也是16个字节。
    (3)user对象有两个变量①String name,int age 。压缩时:此时1和2为12个字节,3为4+4=8字节。一共是20字节,不能整除8,所以4 padding要补齐4个成24字节。
    所以这样的user对象在内存中占24个字节。

四.锁升级过程
说明:在markword的8个字节64位下,保存锁信息,GC信息等。其最后三位的第一位表示偏向锁,最后两位表示普通锁位。
(1)对象刚被new出来。最后三位是0,无锁。
(2)偏向锁:偏向于第一个线程(没有锁,不跟操作系统申请重量级锁)贴标签。执行过程 比如张三要上厕所,然后就给厕所门上贴一个标签为他的名字,也就是自己的线程id这就是偏向锁。
当有别的线程来时,发生任意竞争,就会自动升级为轻量级锁。
(3)轻量级锁:又叫自旋锁(CAS)。执行过程 比如王五这时也来上厕所了发现厕所有标签了,那么他俩开始抢,利用CAS,先撤销偏向锁状态,然后张三,王五自己的线程栈存的自己的对象(lockrecord),抢,看谁的这个指针最后能指向厕所门。谁抢到了,谁的lockrecord指针就指向厕所门。
此时,偏向锁状态下,锁不在队列中等待,太消耗CPU了,所以再次升级为重量级锁。系统定的自旋超过10次,或者自旋的线程数超过CPU的二分之一就升级(jdk1.6之后,由JVM开自动控制)。
(4)重量级锁:(markword指向互斥量的指针)synchronized。

五. synchronized底层的五层实现
(1)java代码:加synchronized
(2)class字节码:编译
(3)执行过程中自动锁升级:new 偏向锁 轻量级锁 重量级锁。
(4)lock comxchg指令

六.volatile的特性:
(1)线程可见性
(2)防止指令重排序
实现:被volatile修饰的变量在编译成字节码文件时会多个lock指令,该指令在执行过程中会生成相应的内存屏障,以此来解决可见性跟重排序的问题。
内存屏障的作用:
1.在有内存屏障的地方,会禁止指令重排序,即屏障下面的代码不能跟屏障上面的代码交换执行顺序。
2.在有内存屏障的地方,线程修改完共享变量以后会马上把该变量从本地内存写回到主内存,并且让其他线程本地内存中该变量副本失效(使用MESI协议)
volatile是“轻量级”synchronized,保证了共享变量的“可见性”(JMM确保所有线程看到这个变量的值是一致的),使用和执行成本比synchronized低,因为它不会引起线程上下文切换和调度。

volatile的变量在进行写操作时,会在前面加上lock质量前缀。
Lock前缀,Lock不是一种内存屏障,但是它能完成类似内存屏障的功能。Lock会对CPU总线和高速缓存加锁,可以理解为CPU指令级的一种锁。
而Lock前缀是这样实现的
它先对总线/缓存加锁,然后执行后面的指令,最后释放锁后会把高速缓存中的脏数据全部刷新回主内存。
在Lock锁住总线的时候,其他CPU的读写请求都会被阻塞,直到锁释放。Lock后的写操作会让其他CPU相关的cache失效,从而从新从内存加载最新的数据,这个是通过缓存一致性协议做的。
锁升级的过程;CAS;对象内存布局问题;object在内存中占几个字节;