You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程环境下TreeMap.put()出现异常行为的原因咨询

问题:多线程下init()方法输出索引不唯一的原因分析

你运行了以下Java代码:

import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;

public final class ThreadTest {
    int N = 4;
    Map<Integer, Proxy> proxy = Collections.synchronizedMap(new TreeMap<>());
    Proxy p;
    
    public static void main(String[] args) {
        new ThreadTest();
    }
    
    public ThreadTest() {
        Thread[] t = new Thread[N];
        for(int c=0;c<N;c++) {
            final int i = c;
            t[i] = new Thread(() -> {
                try {
                    System.out.println( "From thread: " + i );
                    p = new Proxy(i);
                    proxy.put(i, p);
                    p.init();
                } catch (Exception e){}
            });
            t[i].start();
        }
        for(int c=0;c<N;c++) {
            try {
                t[c].join();
            } catch (InterruptedException e){}
        }
    }
    
    public class Proxy {
        int index;
        
        public Proxy(int index) {
            this.index = index;
            System.out.println( "Proxy: " + index );
        }
        
        public void init() {
            System.out.println("Initializing " + index );
        }
    }
}

得到的示例输出如下:

From thread: 0
From thread: 1
From thread: 2
From thread: 3
Proxy: 0
Proxy: 3
Proxy: 2
Proxy: 1
Initializing 3
Initializing 3
Initializing 1
Initializing 2

尽管已使用Collections.synchronizedMap()对TreeMap进行同步,但init()方法输出的索引并非唯一,结果与未同步的Map完全一致,仅调用put()方法却出现索引异常的行为令人费解。


原因分析

  • 问题核心不在synchronizedMap的同步上,而是共享成员变量p的线程不安全访问:
    p是ThreadTest类的实例变量,所有线程共享这同一个变量。当多个线程交替执行p = new Proxy(i);时,会互相覆盖p的指向。比如线程0刚把p赋值为Proxy(0),还没来得及调用init(),线程3就将p替换为Proxy(3),此时线程0再执行p.init()时,实际调用的是线程3创建的Proxy实例的方法,因此会出现重复的"Initializing 3"。
  • Collections.synchronizedMap()仅保证proxy.put(i,p)操作本身是线程安全的,不会出现Map的结构损坏或数据丢失,但它无法管控你对共享变量p的非同步操作。
  • 解决验证:将p改为线程内的局部变量,即把p = new Proxy(i);修改为Proxy p = new Proxy(i);,让每个线程持有独立的Proxy实例,就能避免索引重复的问题。

内容的提问来源于stack exchange,提问作者mike_uvw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 16:05:13