Kafka 0.10.1中CopyOnWriteMap的线程安全性疑问
关于Kafka CopyOnWriteMap中赋值操作原子性的疑问解答
首先可以明确:你担心的“赋值过程中拿到脏对象”的情况不会发生,原因有两点:
1. Java对象引用的赋值是原子操作
在Java虚拟机中,不管是32位还是64位环境,对象引用的赋值操作(即把一个对象的引用赋值给变量)都是原子性的。也就是说this.map = Collections.unmodifiableMap(copy)这个操作,要么完全完成(线程B看到的是全新的不可变Map),要么完全未执行(线程B看到的是旧的Map),绝对不会出现“赋值到一半”的中间状态——不会像C++里对64位整数分两次写入那样产生脏值。
2. volatile关键字的语义保障
你的代码里map变量被声明为volatile,它带来两个关键保障:
- 可见性:线程A完成对
map的赋值后,所有线程能立刻看到这个新的引用值,不会读到缓存的旧数据。 - 禁止指令重排:虚拟机不会把
Collections.unmodifiableMap(copy)的创建指令和this.map = ...的赋值指令重排,确保新的不可变Map完全初始化完成后,才会替换旧的引用,从根源上避免了拿到未初始化完成的对象的可能。
另外补充一点:put方法加了synchronized修饰,这保证了同一时间只有一个线程能执行写操作,不会出现多个线程同时复制Map并替换引用的冲突场景,进一步强化了线程安全。
所以线程B在get方法中调用map.get(k)时,要么拿到旧的完整Map,要么拿到新的完整Map,永远不会出现“脏”的中间状态。
内容的提问来源于stack exchange,提问作者ConnellyM
相关产品推荐
相关产品推荐

