Dubbo 线程污染 DruidDataSource getConnection 报中断异常 interrupt

博文目录

文章目录


JDK Thread interrupt 中断

问题说明

Spring dubbo 服务, 偶尔会报如下异常

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database.  Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: interrupt
...

近期有修改过接口最外层 try-catch, 在 catch 块里添加了 Thread.currentThread.interrupt();

这是一个不当的修改

导致当有请求发生异常时, 线程会被设置中断标记, 然后线程被归还回 Dubbo 线程池, 当之后的某个请求使用了该线程, 执行到 DruidDataSource.getConnectInternal() 方法时, 会加一个可以响应中断的锁, 当有中断异常时, 会抛一个 SQLException(“interrupt”, e), 该方法内部调用到了 AQS.acquireInterruptibly, 里面会先判断当前线程是否被设置了中断标记, 如果有则直接抛出中断异常, 所以最终就抛出了 SQLException, 且 message 为 interrupt

# DruidDataSource.getConnectInternal()
try {
    
    
	lock.lockInterruptibly();
} catch (InterruptedException e) {
    
    
	connectErrorCount.incrementAndGet();
	throw new SQLException("interrupt", e);
}
# java.util.concurrent.locks.ReentrantLock#lockInterruptibly
public void lockInterruptibly() throws InterruptedException {
    
    
    sync.acquireInterruptibly(1);
}
# java.util.concurrent.locks.AbstractQueuedSynchronizer#acquireInterruptibly
public final void acquireInterruptibly(int arg)
         throws InterruptedException {
    
    
     if (Thread.interrupted())
         throw new InterruptedException();
     if (!tryAcquire(arg))
         doAcquireInterruptibly(arg);
 }

问题解决

删除不当位置的 Thread.currentThread.interrupt();

建议, 除非你真的知道为什么需要 Thread.currentThread.interrupt();, 否则不要瞎用

要用也是在 InterruptedException 的 catch 中用, 不要在 Throwable / Exception 级别的 catch 中用

猜你喜欢

转载自blog.csdn.net/mrathena/article/details/124840169