多线程QA

多线程真的难啊 家人萌

2.1  讲一下synchronized关键字的底层原理?

    是什么->修饰谁->底层->过程
synchronized 是 JVM 层面的同步机制,主要用来保证同一时间只有一个线程进入临界区。  
如果修饰代码块,编译后会生成 `monitorenter` 和 `monitorexit` 指令;如果修饰方法,会在方法上加同步标记。  
它底层和对象头里的 Mark Word 以及 Monitor 有关,每个 Java 对象都可以作为锁对象。线程抢锁成功后,会成为这个 Monitor 的 Owner;其他线程竞争失败会进入 EntryList 阻塞;如果线程调用了 `wait()`,会进入 WaitSet。锁释放后,EntryList 里的线程会重新竞争锁,这个竞争不是公平的。  
另外 synchronized 是可重入锁,JDK 1.6 之后也做了锁优化,比如偏向锁、轻量级锁、重量级锁,只有竞争比较激烈时才会膨胀成重量级锁,这时候阻塞和唤醒线程的成本会比较高。

2.2  synchronized 的锁升级过程是什么?偏向锁、轻量级锁、重量级锁分别适合什么场景?

synchronized 不是一上来就使用重量级锁,JVM 会根据竞争情况做锁优化。  
早期常说的锁状态包括偏向锁、轻量级锁和重量级锁。偏向锁适合长时间只有一个线程反复进入同步块的场景,它会把线程 ID 记录到对象头 Mark Word 里,后续同一个线程再进入时,基本只需要判断是不是自己。  
如果有其他线程也来使用这把锁,偏向锁可能会被撤销,进入轻量级锁。轻量级锁适合线程交替执行、竞争不激烈的场景,底层主要通过 CAS 修改对象头 Mark Word 来尝试加锁。  
如果竞争变得激烈,比如 CAS 一直失败,线程需要阻塞,就会膨胀成重量级锁。重量级锁底层依赖 Monitor,涉及线程阻塞和唤醒,成本会更高。  
另外偏向锁要注意版本问题,JDK 15 之后默认已经禁用了,所以面试里可以作为历史优化机制来说,但不能简单认为现在默认一定有偏向锁。

2.3  你谈谈 JMM(Java 内存模型)

JMM,也就是 Java 内存模型,它主要是用来规范多线程环境下共享变量的读写规则。  
可以简单理解为,共享变量存放在主内存中,每个线程有自己的工作内存,线程操作变量时,通常是操作自己工作内存里的副本,线程之间不能直接访问对方的工作内存,只能通过主内存来完成数据同步。  
但这个模型不是单纯讲存储位置,它真正要解决的是并发里的三个问题:可见性、有序性和原子性。比如一个线程改了变量,另一个线程什么时候能看到,这是可见性;编译器和 CPU 可能会做指令重排序,这是有序性;像 `i++` 这种复合操作不是原子的,就涉及原子性问题。  
Java 里像 `volatile`、`synchronized` 以及 happens-before 规则,都是围绕 JMM 来保证这些并发语义的。比如 volatile 能保证可见性和禁止指令重排序,synchronized 既能保证互斥,也能保证释放锁前的修改对后续加锁线程可见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值