Java对象实例

android自旋锁 synchronized自旋锁实现_多线程

 

 

 对象头:由MarkWord(32位),Class Metadata Address(类的元数据地址,即对象指向它的类的元数据的指针,32位),数组长度(当对象为数组时,32位)。

MarkWord

android自旋锁 synchronized自旋锁实现_无锁_02

Monitor: 是一个同步工具,内置于每一个对象中的监视器,每个对象都有一个Monitor,相当于一个许可证(锁),拿到许可证才能访问对象。

android自旋锁 synchronized自旋锁实现_无锁_03

 Synchronized在1.6以后的优化

无锁  > 偏向锁 > 轻量级锁 > 重量级锁。增加了偏向锁和轻量级锁。

android自旋锁 synchronized自旋锁实现_无锁_04

自旋锁和自适应自旋

线程的挂起和恢复会极大的影响开销。并且jdk官方人员发现,很多线程在等待锁的时候,在很短的一段时间就获得了锁,所以它们在线程等待的时候,并不需要把线程挂起,而是让他无目的的循环,一般设置10次。这样就避免了线程切换的开销,极大的提升了性能。

而适应性自旋,是赋予了自旋一种学习能力,它并不固定自旋10次一下。他可以根据它前面线程的自旋情况,从而调整它的自旋,甚至是不经过自旋而直接挂起。

锁消除

对不存在线程安全的锁进行消除。

锁粗化

如果jvm检测到有一串零碎的操作都对同一个对象加锁,将会把锁粗化到整个操作外部,如循环体。

 偏向锁

大部分情况锁不仅不存在多线程竞争,而是总是由同一个线程多次获得(局部性原理)。

当一个线程访问加了synchronized的对象时,如果是无锁状态,则加偏向锁,即用CAS更改MarkWord的锁标记位,并把线程id也写进MarkWord。该线程退出后,偏向锁依然保留。

下次这个线程再次访问,就不需要CAS修改MarkWord锁标记位和线程id,只需要对比MarkWord的线程id是不是自己的即可。

如果成功,直接访问对象。

如果对比失败,则看标记位,

  如果是无锁状态,CAS加偏向锁。

  如果是偏向锁,此时无法判断加偏向锁的上一个线程是否正在访问对象或已离开,所以升级为轻量级锁。

轻量级锁

引入轻量级锁的主要目的是在多线程竞争不激烈的情况下,通过CAS竞争锁,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。轻量级锁是乐观锁。

1,线程在自己的栈桢中创建锁记录 LockRecord,锁记录包括MarkWord(从对象头复制)和Owner指针(存放对象地址,也就是指向对象的指针)。

2,用CAS操作把对象头的MarkWord改为指向线程栈帧的锁记录的指针(锁记录的地址)。

如果获取锁失败,自旋或则自适应自旋,超过一定次数,则升级为重量级锁。

重量级锁

利用对象内的Monitor实现,Monitor底层是操作系统的MutexLock(互斥锁)实现的。操作系统实现线程之间的切换需要从用户态到内核态的切换,切换成本非常高。

 

-