谈谈你对synchronized的理解

发布时间:2023年12月27日

面试须知(手动狗头)

面试官:

描述一下你对synchronized的理解。

小羊:

  1. synchronized作为关键字,它可以用于修饰方法、代码块,属于独占锁、可重入锁、悲观锁、非公平锁。
  2. 当synchronized修饰方法时,锁住的当前对象,在字节码文件中我们能够在方法的标识位中多了 ACC_SYNCHRONIZED 标识。jvm会通过判断标识位来判断他是否是一个同步方法。
  3. 当synchronized修饰代码块时,会在代码块前后加上monitorenter 和monitorexit来标识。
  4. 每一个对象都有一个monitor监视器与之对应。monitor中存在一个state记录当前的锁状态,0是无锁,获取锁的线程每加一次锁,state+1,每释放一次锁,state-1。
  5. 对象头中包含了锁的标识位。当synchronized加锁时,会将指向monitor的指针写入这个对象的Header中,然后将这个对象的锁标识位由 00变为10。(扩展:对象最少占多少个字节?)
  6. 在jdk1.6之后synchronized加入了偏向锁和轻量级锁的概念。synchronized加锁的过程变成了无锁-》偏向锁-》轻量级锁-》重量级锁。(扩展:锁膨胀的过程)

synchronized的几种用法:

首先我们先说synchronized的用法:
1.修饰实例方法

public synchronized V merge() {}

2.修饰静态方法

public synchronized static void write() {
    
}

3.修饰代码块

private void writeObject(java.io.ObjectOutputStream s)
        throws IOException {
    synchronized (this) {
       
    }
}

锁膨胀的过程

以下内容不记得是来源于哪里了,我以前的笔记里记的。

偏向锁: MarkWord存储的是偏向的线程ID;
轻量锁:MarkWord存储的是指向线程栈中Lock Record的指针;
重量锁:MarkWord存储的是指向堆中的monitor对象的指针

如下所示,锁主要存在四种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,他们随着竞争的情况逐渐升级。

(1)、对象最开始是无锁状态的001;

(2)、偏向锁,顾明思义,他会偏向于第一个访问的线程。第一个使用该对象的线程对该对象加synchronized操作后便是是偏向锁101,默认以后只有这个线程使用该对象,若果偏向锁开关没开的话这时候加锁的便是轻量级锁00了;这样设计偏向锁的的好处是:如果自始至终使用该对象的线程真的只这有一个的话,很明显几乎就没有什么额外的开销,性能极高,毕竟需要加锁的对象是少数,适合大多数的对象的情况。偏向锁是不可逆的,一旦某个线程加上了偏向锁就不会回到无锁状态了。

(3)、当再来第二个线程通过CAS加锁,这时候如果能加锁成功,是轻度的竞争,对象就变为轻量级锁00。因为此时是新来的线程,对象头中存入的是之前的偏向线程,只要新来的线程和之前的偏向线程不是同一个线程就会变为轻量级锁,就会消除对象上的偏向锁;

(4)、如果步骤三中的的对象正在拿着轻量级锁,此时再来新的线程竞争的话,如果能够通过CAS获取到锁便还好还是轻量级锁;如果竞争拿不到锁,便通过自旋或者自适应自旋来获取,如果能成功便还是轻量级锁;如果自旋不成功或者有大量的线程竞争锁资源,便会升级为重量级锁。
(5)、 升级成为重量级锁的过程就是当一个线程给一个对象上重量级锁的时候会尝试获取它的锁资源,然后这个锁资源会关联一个monitor监视器对象,将monitor的锁定状态+1,并且将monitor的指针写入到一个对象头中,然后将锁标志位改为10。然后加锁时会执行一个monitorenter方法。在释放锁时会执行monitorexit方法。
当其他线程来尝试获取锁资源时,会发现monitor监视器中锁的状态不为0,那么就会在monitor的监视状态下去等待这个锁资源。
然后synchronized是一个可重入锁,一个线程重复获取锁资源每获取一次会给锁状态+1,每释放一次会使monitor锁状态-1,直到锁状态为0那么释放锁资源。(这个是同步代码块的原理)

在这里插入图片描述
无锁:
在这里插入图片描述

对象最少占多少个字节

一个对象最少占16个字节,如果包含栈中的引用,那么最少占20个字节。

头信息占12个字节:

1)markword 8字节 用来存储锁信息,哈希码,gc信息

2)classpoint 4字节

实例数据:没有就是0个字节

对齐填充:用于确保对象的大小能够被8整除,如果不能被整除那么填充到能被整除。

markword如图所示:
在这里插入图片描述

大家好,我是小羊炒饭。感谢大家的关注,有任何问题可以提出,我们一起学习共同进步。从今天开始每周至少会有一篇纵向学习和分析java代码和框架的文章。公司的前辈告诉我,想涨工资人情>技术,我不懂人情,所以我想深耕技术,希望有一天能涨工资哈哈。

文章来源:https://blog.csdn.net/qq_45948401/article/details/135214862
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。