首页 > 编程知识 正文

对象锁 java,java类对象和实例对象

时间:2023-05-06 20:38:29 阅读:129812 作者:1651

对象由多个部分构成,是对象标题、属性字段、补充区域等。 补充区域是指,如果对象的总大小不是4字节的整数倍,则会填充前面的内存地址,使其成为整数倍。

后面的两个很好理解。 今天主要想总结一下对象的头部:

对象的开头部分位于对象的开头,包含两个或三个部分: ssdby Words和Klass Words。 如果对象是数组,则还可能包括数组的长度。

Klass Word包含32位或64位地址,是当前对象所属类的地址,可以从该地址获取元数据信息。

ssdby Word需要重点说明,它主要包括目标散列值、年龄段、锁定标志等,大小为32位或64位

如果对象处于不同的锁定状态,ssdbyWord中的将被不同的替换,如下表所示。

1、如果对象未被锁定,则lock标志位为0到1,包括哈希值、年龄段、偏转锁定标志位等,其中偏转锁定标志位为0;

2、对象进行偏转锁定时,哈希值和部分无用内存将转换为锁定所有者的线程信息和锁定时间戳epoch。 此时,lock标志位不变,偏转锁定为1。 也就是说,偏转锁定和lock标志位都决定是否偏向锁定状态。

偏转锁定的锁定步骤:

轻松确定加载和测试,即当前线程id是否与ssdbyword中的线程id匹配。

如果匹配,则表明线程已成功锁定,然后继续执行以下代码。

如果不匹配,则检查对象是否仍可偏转,即“是否已偏转到锁定”标志位的值。

如果尚未偏转,则利用CAS操作竞争锁定。 也就是说,第一次获取锁定时的操作。

3、发生锁定冲突时,偏转锁定为轻型锁定。 这种情况下,需要先解除偏转锁定。 这个步骤也消耗了相当大的性能。 在轻型锁定的ssdby Word中,lock标志位为00,其馀内容由指针替换,指向堆栈中的锁定记录。

解锁的过程包括:

在安全点停止具有锁定的线程。

遍历线程堆栈,如果有锁定记录,则必须修复锁定记录和ssdbyword,使其处于未锁定状态。

启动当前线程,将当前锁升级为轻量锁。

因此,在某些同步代码块中,如果两个或多个线程经常发生冲突,偏转锁定就会变得很麻烦。 在这种情况下,可以从一开始就关闭默认的偏转锁定功能

轻型锁定的锁定步骤:

线程在自己的堆栈帧中创建锁定记录LockRecord。

将锁定对象的对象标题中的ssdbyWord复制到刚刚创建线程的锁定记录中。

将锁定记录中的Owner指针指向锁定对象。

将锁定对象头部的ssdbyWord替换为指向锁定记录的指针。

轻型锁主要有旋转锁和自适应旋转锁两种。 自旋锁很可能浪费CPU,导致锁不公平; 自适应是根据上一个线程是否成功或多久获取一次锁定来设置转速,这样,如果上一次失败,就很可能直接进入重量锁定

4、竞争线程增加,锁定持续膨胀,到重锁时,也是互斥锁,即同步,其锁定标志位为10,ssdby Word的其馀内容位于指向目标监视器的指针上

特别是,如果此对象已经在GC中标记,则锁定为11,不包含其馀内容。

监视器对象

每个对象都与Monitor对象相关联,Monitor对象中记录有具有锁定的线程信息、队列等。 Monitor对象包含三个字段:

_owner记录当前保持锁定的线程

_EntryList是一个队列,用于阻止所有等待锁定的线程

_WaitSet也是一个队列,用于记录尚未被通知调用wait ()方法的线程

如果线程具有锁定,则信息(如线程id )将复制到owner字段,其馀线程将进入块队列入口列表。 如果拥有锁定的线程执行wait方法,它将立即解锁并进入waitset,而线程解锁时owner将为空。 在公平的锁定条件下,条目列表中的线程将竞争锁定,并竞争成功的线程id

监视器和同步

对于同步代码块,JVM会在进入代码块之前添加监视器enter。 成功进入monitor后,线程将获得锁,一个对象的monitor在同一时间只能被一个线程锁占用。

对于同步方法,JVM将为方法设置ACC_SYNCHRONIZED标志,调用时JVM将根据该标志确定是否为同步方法。

在同步中锁定对象会阻止线程并切换线程的状态。 因为要切换线程状态,操作系统必须运行,所以必须将用户状态切换到内核状态。 此切换可能需要很长时间,而且比用户执行代码需要更长时间。

同步是JVM级锁定,并不断优化。 现在,同步不再像以前那么“沉重”。 也就是说,这可能是同步在诸如ConcurrentHashMap之类的JUC包源中大量使用的原因

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。