Kotlin中synchronized块后的also块是否存在并发变量安全问题
结论
不会出现你担心的it变量在执行logger.log前被其他线程修改的问题。
核心原因
- 先理清楚这段代码的严格执行顺序:
- 线程跑到
synchronized(this)时先争抢this的监视器锁,拿到锁才会执行块内逻辑,最终生成你要的String结果 - 同步块内所有逻辑跑完,会先把生成的String作为同步块的返回值固定存到当前线程的操作数栈,之后才会执行锁释放动作
- 锁完全释放后,才会调用
.also方法,把之前已经存好的String引用作为参数传入lambda,也就是你代码里的it
- 线程跑到
- 从变量存储特性看:
it是每个线程执行这段代码时,在自己的调用栈帧上生成的局部临时变量,属于线程私有的数据,其他线程根本没有访问这个局部变量的入口,完全不可能修改它的值。 - 还有两层额外保障:
- 你这里同步块返回的是
String类型,Kotlin/Java里的String本身就是不可变类,就算其他线程凑巧拿到同一个String的引用,也改不了字符串的内容 - Kotlin里lambda的隐式参数
it默认是final修饰的,别说其他线程,当前执行的线程自己都没法在also块里给it重新赋值。
- 你这里同步块返回的是
容易踩的认知误区
不少人误以为also块写在synchronized括号外面,就会因为锁提前释放导致变量被篡改,实际上同步块的返回值是在持锁阶段就已经计算完成、完成值传递的,锁释放动作根本碰不到已经确定的返回值。
唯一可能出现可见性问题的场景是:你同步块返回的是可变对象(比如自定义可变类、ArrayList这类非线程安全的集合),且其他线程持有这个对象的引用去修改它的内部属性——但这时候改的是堆上对象的内部内容,不是it变量本身存的引用值,和你问的“it变量被修改”完全是两个概念。
内容的提问来源于stack exchange,提问作者Milad Amery
相关产品推荐
相关产品推荐

