Spring组件多线程读写时,引用赋值需加锁吗?引用赋值是否原子?
问题解答
1. 对象引用赋值的原子性
Java中对象引用的赋值操作是原子操作。比如你代码里的listFromDynamo = result;,多线程环境下不会出现"半赋值"的中间状态——读线程要么拿到旧的List引用,要么拿到新的List引用,不会获取到无效的部分赋值状态。
注意:原子性仅保证引用赋值本身的完整性,不涉及List内部元素的可见性和指令有序性。
2. 当前场景是否需要并发锁?
不需要额外加锁,但要做一处小修改保证线程安全:
为什么不需要锁?
你的更新逻辑是先在写线程本地创建全新的ArrayList,完成DynamoDB数据填充后,再将新List的引用赋值给listFromDynamo。读线程完全看不到新List的填充过程,只会拿到完整的旧List或完整的新List,不会读到部分填充的无效List。
必须的修改:保证可见性
虽然赋值是原子的,但默认情况下读线程可能缓存listFromDynamo的旧值,无法及时感知到写线程的更新。需要给listFromDynamo添加volatile关键字:
private volatile List<ClassFromDyanmo> listFromDynamo;
volatile的作用:
- 禁止指令重排序,确保写线程的赋值操作完成后才会被读线程感知
- 保证变量的可见性,写线程修改后,读线程能立即获取到最新引用
额外优化建议
- 可以把返回的List设置为不可变,避免读线程误修改List内容(防御性编程):
在updateListFromDynamo方法最后转换为不可变List:
或者在listFromDynamo = Collections.unmodifiableList(result);getListFromDynamo方法中返回不可变版本:public List<ClassFromDyanmo> getListFromDynamo() { return Collections.unmodifiableList(listFromDynamo); }
内容的提问来源于stack exchange,提问作者eweiss
相关产品推荐
相关产品推荐

