当线程全部为空时,C3P0 明显死锁?

Posted

技术标签:

【中文标题】当线程全部为空时,C3P0 明显死锁?【英文标题】:C3P0 apparent deadlock when the threads are all empty? 【发布时间】:2011-04-13 10:48:32 【问题描述】:

我在 Tomcat 中使用 C3P0 作为连接池,我看到非常令人担忧的错误:

2010-09-16 13:25:00,160 [Timer-0] WARN  com.mchange.v2.async.ThreadPoolAsynchronousRunner  - com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@43502400 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
2010-09-16 13:25:01,407 [Timer-0] WARN  com.mchange.v2.async.ThreadPoolAsynchronousRunner  - com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@43502400 -- APPARENT DEADLOCK!!! Complete Status:
  Managed Threads: 10
  Active Threads: 0
  Active Tasks:
  Pending Tasks:
    com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@6e4151a7
  Pool thread stack traces:
  Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#6,5,main]
    java.lang.Object.wait(Native Method)
    com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:534)
  Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2,5,main]
    java.lang.Object.wait(Native Method)
    com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:534)
  Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1,5,main]
    java.lang.Object.wait(Native Method)
    com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:534)
  Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0,5,main]
    java.lang.Object.wait(Native Method)
    com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:534)
  Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#5,5,main]
    java.lang.Object.wait(Native Method)
    com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:534)
  Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#4,5,main]
    java.lang.Object.wait(Native Method)

... many more, exact same stack trace

第 534 行是:

 while (true) 
   Runnable myTask;
   synchronized ( ThreadPoolAsynchronousRunner.this ) 
     while ( !should_stop && pendingTasks.size() == 0 )
       ThreadPoolAsynchronousRunner.this.wait( POLL_FOR_STOP_INTERVAL ); // <- here
     if (should_stop) ...

看起来所有线程都处于空闲状态。他们在等工作。 0 个活动线程,只有 1 个任务要完成。关于出了什么问题的任何线索?

这是配置:

ds.setUser(userName);
ds.setPassword(password);
ds.setMaxPoolSize(16);
ds.setMaxConnectionAge(1800);
ds.setAcquireRetryAttempts(4);
ds.setMaxIdleTime(900);
ds.setNumHelperThreads(10);
ds.setCheckoutTimeout(1000);

【问题讨论】:

您能解决您的问题吗? (我知道已经很久了) @Ittai:不,但它最终消失了。不知道到底是什么修复了它:-( 【参考方案1】:

我刚刚遇到了针对 Oracle 数据库的类似问题,但就我而言,Managed ThreadActive Thread 的计数相同。

    Managed Threads: 3
    Active Threads: 3

对我来说,这实际上是一个身份验证错误,但由于我进行登录审核的方式而显示为 APPARENT DEADLOCK 错误。

    2013-08-12 11:29:04,910 [Timer-4] WARN  com.mchange.v2.async.ThreadPoolAsynchronousRunner: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@34996454 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
    2013-08-12 11:29:04,914 [Timer-4] WARN  com.mchange.v2.async.ThreadPoolAsynchronousRunner: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@34996454 -- APPARENT DEADLOCK!!! Complete Status: 
            Managed Threads: 3
            Active Threads: 3
            Active Tasks: 
                    com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@6730b844 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2)
                    com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@2f91ad49 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0)
                    com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@507ac05 (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1)
            Pending Tasks: 
                    com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@3aae7ed7
    Pool thread stack traces:
            Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2,5,main]
                    java.net.SocketInputStream.socketRead0(Native Method)
                    java.net.SocketInputStream.read(SocketInputStream.java:150)
                    java.net.SocketInputStream.read(SocketInputStream.java:121)
                    oracle.net.ns.Packet.receive(Packet.java:300)
                    oracle.net.ns.DataPacket.receive(DataPacket.java:106)
                    oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:315)
                    oracle.net.ns.NetInputStream.read(NetInputStream.java:260)
                    oracle.net.ns.NetInputStream.read(NetInputStream.java:185)
                    oracle.net.ns.NetInputStream.read(NetInputStream.java:102)
                    oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:124)
                    oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:80)
                    oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1137)
                    oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:290)
                    oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
                    oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:380)
                    oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:760)
                    oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:401)
                    oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:546)
                    oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:236)
                    oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
                    oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:521)
                    com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:134)
                    com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:182)
                    com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:171)
                    com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:137)
                    com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1014)
                    com.mchange.v2.resourcepool.BasicResourcePool.access$800(BasicResourcePool.java:32)
                    com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1810)
                    com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
            Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0,5,main]
                    java.net.SocketInputStream.socketRead0(Native Method)
                    java.net.SocketInputStream.read(SocketInputStream.java:150)
                    java.net.SocketInputStream.read(SocketInputStream.java:121)
                    oracle.net.ns.Packet.receive(Packet.java:300)
                    oracle.net.ns.DataPacket.receive(DataPacket.java:106)
                    oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:315)
                    oracle.net.ns.NetInputStream.read(NetInputStream.java:260)
                    oracle.net.ns.NetInputStream.read(NetInputStream.java:185)
                    oracle.net.ns.NetInputStream.read(NetInputStream.java:102)
                    oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:124)
                    oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:80)
                    oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1137)
                    oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:290)
                    oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
                    oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:380)
                    oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:760)
                    oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:401)
                    oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:546)
                    oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:236)
                    oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
                    oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:521)
                    com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:134)
                    com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:182)
                    com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:171)
                    com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:137)
                    com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1014)
                    com.mchange.v2.resourcepool.BasicResourcePool.access$800(BasicResourcePool.java:32)
                    com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1810)
                    com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
            Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1,5,main]
                    java.net.SocketInputStream.socketRead0(Native Method)
                    java.net.SocketInputStream.read(SocketInputStream.java:150)
                    java.net.SocketInputStream.read(SocketInputStream.java:121)
                    oracle.net.ns.Packet.receive(Packet.java:300)
                    oracle.net.ns.DataPacket.receive(DataPacket.java:106)
                    oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:315)
                    oracle.net.ns.NetInputStream.read(NetInputStream.java:260)
                    oracle.net.ns.NetInputStream.read(NetInputStream.java:185)
                    oracle.net.ns.NetInputStream.read(NetInputStream.java:102)
                    oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:124)
                    oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:80)
                    oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1137)
                    oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:290)
                    oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)
                    oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:380)
                    oracle.jdbc.driver.T4CTTIoauthenticate.doOAUTH(T4CTTIoauthenticate.java:760)
                    oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:401)
                    oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:546)
                    oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:236)
                    oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
                    oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:521)
                    com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:134)
                    com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:182)
                    com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:171)
                    com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:137)
                    com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1014)
                    com.mchange.v2.resourcepool.BasicResourcePool.access$800(BasicResourcePool.java:32)
                    com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1810)
                    com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)

【讨论】:

好厉害!在进行了一些重大的架构更改后,我遇到了这个错误,所以我认为我搞砸了。真正的原因与您的回答有关——因为我无法通过防火墙进入数据库服务器! 现在有同样的问题。再次因为防火墙规则。 @HankCa 感谢您的领导。 对我来说 100% 正确,aws 安全组。 @HankCa - 你应该发表你的评论作为答案 - 你节省了我几个小时不那么有趣的调试 - 谢谢! @HankCa 我面临同样的问题。一旦记录了问题,它就会不断记录,应用程序响应变得不可预测。我们在aws上,在这种情况下可以采取哪些纠正步骤【参考方案2】:

这听起来你已经从池中获取了一个连接,没有及时返回。

C3P0 在获取连接但未在死锁检测超时时间内返回池时确定“明显死锁”。

如果将连接获取移近“动作”并在数据库工作完成后立即将其返回到池中,此消息将消失。

【讨论】:

文档说 setMaxAdministrativeTime 默认为 0(即永远)。此外,为什么我必须在任何固定的时间限制内返回到池的连接?我已经检查过了;只要我需要它就应该是我的……即使不是,这也不是僵局! 你是对的,这就是警告说明显死锁的原因。顺便说一句,你使用了一个连接池,所以你不需要在不使用它的时候保持连接 当然可以,但是有问题的地方可能在一个长期运行的事务中;在此期间您无法释放它。 这应该不会导致问题,根据我的经验,C3P0 检查连接是否被积极使用。我不习惯直接使用 C3P0,我将它与 Hibernate 一起使用 - 但在这种情况下,长事务永远不会成为问题,但空闲连接会导致您收到警告。 刚刚看到您对问题的编辑。您命中的超时由“ds.setMaxIdleTime(900)”设置【参考方案3】:

这会解决你的问题

ds.setMaxStatements(1000);
ds.setMaxStatementsPerConnection(100); (the maximum number of prepared statments your system can execute on a single connection)

签出:https://forum.hibernate.org/viewtopic.php?t=947246&highlight=apparent+deadlock+c3p0

完成后记得关闭你的陈述!!

【讨论】:

【参考方案4】:

我对答案https://***.com/a/18192588/1019307 的评论收到了足够多的赞成票,表明它应该是一个答案。

我收到此错误是因为我无法通过防火墙访问数据库服务器。请检查这是否是您的问题。

【讨论】:

【参考方案5】:

@eebbesen,我遇到了和你一样的错误。我正在运行 Tomcat 9.0.6 版。我的 Maven 项目中有休眠核心版本 5.2.10,休眠 c3p0 版本 3.6.3。我的不是身份验证错误,而是由于我之前更改了计算机的名称。这对 tomcat 没有立即影响,但是在我的机器重新启动后,当我尝试通过 eclipse(Oxygen 2)再次启动 tomcat 时,由于您提出的问题,我无法再启动 eclipse。

我用谷歌搜索了这个,我发现了这个链接,它提示我解决了这个问题:

https://community.oracle.com/thread/339825

上面写着:

先看看OracleServiceXE和OracleXETNSListener服务是否 跑步。将 url 中的 127.0.0.1 替换为您的 IP 或名称 机器。它必须与 tnsnames.ora 文件中声明的主机匹配。

后来它提到在哪里可以找到这个 tnsnames.ora 文件,对我来说它就在这里:

C:\oraclexe\app\oracle\product\11.2.0\server\network\ADMIN

查看这个 tnsnames.ora 文件,我看到了这个:

XE =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = MyMachineName-7)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = XE)
    )
  )

但我最近将我的机器重命名为 MyMachineName-5。我将 7 更改为 5 并保存了文件。我检查了这个目录中的“listener.ora”文件,它有同样的问题:

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
      (ADDRESS = (PROTOCOL = TCP)(HOST = MyMachineName-7)(PORT = 1521))
    )
  )

我将 7 更改为 5 并保存了文件。

然后我打开任务管理器,单击“服务”选项卡,然后查看“Oracle”服务。我重新启动了:OracleXETNSListener、OracleXEClrAgent、OracleServiceXE。又去eclipse里重启tomcat,这次又出问题了。

附录:

我也用谷歌搜索了这个:

https://community.oracle.com/thread/2267906

这引导我尝试:

1) 在 Windows Defender 中关闭了防火墙(已经关闭了 mcaffee 防火墙)

2) 启动 sqlplus 以确保我可以使用我在休眠文件中使用的凭据登录:hibernate.cfg.xml

C:\oracle\app\oracle\product\11.2.0\server\bin\sqlplus.exe

3) 启动 Oracle Database 11g 的桌面快捷方式

即使我修复了机器名称问题,这对我来说还是失败了,我仍然需要调查。

4) 使用 dbVisualizer,我尝试连接到 Oracle。这仅在我解决了 .ora 文件机器名称问题后才有效:双击连接并单击“ping 服务器”按钮。

【讨论】:

【参考方案6】:

我也遇到过同样的问题,但原因有点难以发现,因为它是由一些同时尝试获取连接的资源引起的。

如您所见,如果池尚未初始化,则提供的代码通过调用设置函数来初始化它。

public Connection getConnection() throws SQLException 
    if (mCPDS == null) 
        setupPool();
    

    return mCPDS.getConnection();

问题是许多资源在程序开始时试图获取连接,所以一段时间后有多个资源实例化池导致您的问题。

解决方案只是声明方法同步,以在调用该方法时将其他资源排除在外,并且它仍在实例化池中。

public synchronized Connection getConnection() throws SQLException 
    if (mCPDS == null) 
        setupPool();
    

    return mCPDS.getConnection();

这可能是不使用单例的设计错误,但解决了缺乏一些性能的问题。

【讨论】:

【参考方案7】:

我们遇到了这个问题,并通过将其添加到 C3P0 配置中解决了它:

<property name="statementCacheNumDeferredCloseThreads" value="1"/>

根据:this from the C3P0 doc

【讨论】:

【参考方案8】:

通过正确关闭 Statement 和 Resultset 实例(不知何故未关闭)解决了同样的问题(无法检测到):

String SQL = "SELECT 1";
try 
    con = DriverManager.getConnection(host, userName, userPassword);
    stmt = con.prepareStatement(SQL, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
    try 
        rs = stmt.executeQuery(SQL);
        try 
            rs.next();
            // ...
         finally 
            rs.close();
        
     finally 
        stmt.close();
    
 catch (SQLException ex) 
    Logger.getLogger(MyClass.class.getName()).log(Level.SEVERE, null, ex);

【讨论】:

【参考方案9】:

您好,我的朋友只是发表评论,我有同样的情况。我刚刚配置了我的spring-hibernate eclipse项目,出现了同样的异常,需要注意的是我的项目还是没有任何查询。

我通过以下步骤解决了这个问题:

1) 清理项目:项目--> 清理... 2)构建项目:项目-->构建项目

我希望它对你有用。

【讨论】:

【参考方案10】:

我突然遇到了同样的问题:在注意到只有在调试模式下启动我的应用程序时才存在死锁(我正在使用 IntelliJ)并且在正常运行时运行良好,我开始挖掘它.

我终于发现一个断点阻塞了连接:我不知道为什么 Intellij 没有“监听”应用程序正在通过那个断点,而是因为断点而被挂在某个地方,这是导致明显的死锁

在我的项目中删除所有断点后,一切又开始顺利。

希望这对某人有所帮助

【讨论】:

【参考方案11】:

在 glassfish4 服务器上部署应用程序时遇到了类似的问题。原来这是一个数据库配置问题。只需确保您的数据库连接配置正确,验证配置中提供的主机名是否允许连接到数据库。尝试使用配置的用户名和主机名/域手动连接到数据库。如果需要,允许 db 用户从所需的域进行连接。使用正确的数据库配置重建应用程序,然后部署它。

【讨论】:

以上是关于当线程全部为空时,C3P0 明显死锁?的主要内容,如果未能解决你的问题,请参考以下文章

自定义生产者消费者

休眠“明显的死锁!!!为未分配的挂起任务创建紧急线程!”

连接池详解,c3p0与dbcp的区别!

Java基础_死锁线程组定时器Timer

java中多线程产生死锁的原因以及解决意见

Java 死锁及解决方法