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

Java线程synchronized失效问题:连接池获取连接异常求助

让我来帮你排查一下代码里的问题,主要有几个关键点导致了synchronized失效和连接获取异常:

问题分析

1. 锁对象错误导致同步彻底失效

看AbstractD3Dao里的getCurrentSession()方法:

synchronized (conexao.getInstance()) {
    while (connPool == null) {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        connPool = conexao.getInstance();
    }
}

这里有两个致命问题:

  • 你锁的是conexao.getInstance()返回的MVConnection实例,但每次调用getInstance()都会返回新的可用连接(或等待后返回),这意味着不同线程锁的是完全不同的对象!没有共享锁的情况下,synchronized自然起不到互斥作用,这就是你觉得它"失效"的核心原因。
  • 调用wait()时没有指定对象,实际是对AbstractD3Dao的实例调用wait(),但你当前持有的锁是MVConnection对象的锁,这会触发非法监视器状态异常(即使没抛出,逻辑上也完全混乱),因为wait()必须在持有对应对象锁的前提下调用。

2. 等待/通知机制完全不匹配

getInstance()里的notify()是对ConexaoD3实例调用的,但getCurrentSession()里的wait()是对AbstractD3Dao实例调用的,两者根本不在同一个锁对象的等待队列里,线程永远不会被正确唤醒。

3. 连接查找的死循环浪费资源

getInstance()里用ConcurrentHashMap.search()做并行搜索,找不到可用连接时会进入无限循环空转,严重浪费CPU资源。


修复方案

1. 统一锁对象与等待/通知逻辑

修改getCurrentSession(),确保锁的是固定的ConexaoD3实例,且等待/通知的对象一致:

protected MVConnection getCurrentSession() {
    System.out.println("Abstract request the conn");
    MVConnection connPool = null;
    // 锁ConexaoD3实例本身,而非返回的连接对象
    synchronized (conexao) {
        while (connPool == null) {
            try {
                System.out.println("Aguardando Conexao");
                System.out.println(Thread.currentThread().getName() + " is waiting");
                // 对conexao实例调用wait(),因为我们持有的是它的锁
                conexao.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt(); // 恢复中断状态,避免线程状态异常
            }
            connPool = conexao.getInstance();
        }
    }
    try {
        System.out.println(" Abstract assineg the PIB " + connPool.getServerPort() + "to use");
    } catch (MVException e) {
        e.printStackTrace();
    }
    return connPool;
}

2. 修正getInstance()的同步与通知逻辑

优化连接查找逻辑,确保通知的是同一个锁对象的等待线程:

public synchronized MVConnection getInstance() {
    System.out.println("pass here on getInstance");
    System.out.println("--------------------------------------------------------");
    System.out.println("Before request Instance");
    LogLinhas();
    System.out.println("--------------------------------------------------------");
    MVConnection searchResult = null;
    System.out.println(Thread.currentThread().getName() + " is running");
    
    // 改用普通遍历查找可用连接,避免并行搜索的不必要开销
    for (Map.Entry<MVConnection, Boolean> entry : listaConn.entrySet()) {
        if (entry.getValue()) {
            searchResult = entry.getKey();
            break;
        }
    }
    
    // 没有可用连接直接返回null,让调用方等待(避免死循环空转)
    if (searchResult == null) {
        return null;
    }
    
    // 更新连接状态为忙碌
    listaConn.replace(searchResult, false);
    try {
        System.out.println("Set " + searchResult.getServerPort() + " as busy");
    } catch (MVException e) {
        e.printStackTrace();
    }
    
    // 用notifyAll()唤醒所有等待线程,避免遗漏
    notifyAll();
    System.out.println(Thread.currentThread().getName() + " notifying");
    
    System.out.println("--------------------------------------------------------");
    System.out.println("After request Instance");
    LogLinhas();
    System.out.println("--------------------------------------------------------");
    return searchResult;
}

3. 补充连接释放逻辑(必须)

你现在只实现了连接获取,没有释放逻辑,会导致所有连接被标记为忙碌后,线程永远无法获取连接。添加释放方法:

public synchronized void releaseConnection(MVConnection conn) {
    if (conn != null && listaConn.containsKey(conn)) {
        listaConn.replace(conn, true);
        try {
            System.out.println("Set " + conn.getServerPort() + " as free");
        } catch (MVException e) {
            e.printStackTrace();
        }
        notifyAll(); // 通知等待线程有新的可用连接
    }
}

记得在使用完连接后调用conexao.releaseConnection(conn)释放资源。

4. 可选:用更专业的工具类实现连接池

ConcurrentHashMap并不是连接池的最佳选择,Java自带的BlockingQueue天生支持阻塞等待可用资源,能大幅简化代码:

private BlockingQueue<MVConnection> connectionQueue;

// 初始化时将所有可用连接放入队列
public void initConnections(List<MVConnection> connections) {
    connectionQueue = new ArrayBlockingQueue<>(connections.size(), true);
    connectionQueue.addAll(connections);
}

public MVConnection getInstance() throws InterruptedException {
    // take()会自动阻塞直到有可用连接
    return connectionQueue.take();
}

public void releaseConnection(MVConnection conn) {
    if (conn != null) {
        connectionQueue.offer(conn);
    }
}

这种方式完全不需要手动处理同步和等待/通知,更可靠也更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:51:37