长时间连接导致阻塞的线程?

时间:2017-06-08 13:54:52

标签: java oracle tomcat jdbc

每隔一段时间我就不得不维持一个旧的Java来停止响应。我设法获得了几个线程堆栈跟踪,大多数线程被阻止,试图获得连接:

"tomcat-http-8180-168" - Thread t@10137
   java.lang.Thread.State: BLOCKED
    at oracle.jdbc.pool.OracleImplicitConnectionCache.retrieveCacheConnection(OracleImplicitConnectionCache.java:566)
    - waiting to lock <566080> (a oracle.jdbc.pool.OracleImplicitConnectionCache) owned by "Thread-6" t@29

持有锁的线程显示:

"Thread-6" - Thread t@29
   java.lang.Thread.State: BLOCKED
    at oracle.jdbc.driver.PhysicalConnection.closeLogicalConnection(PhysicalConnection.java:3849)
    - waiting to lock <146da30> (a oracle.jdbc.driver.T4CConnection) owned by "tomcat-http-8180-369" t@17665
    at oracle.jdbc.driver.LogicalConnection.cleanupAndClose(LogicalConnection.java:304)
    at oracle.jdbc.pool.OracleImplicitConnectionCache.closeCheckedOutConnection(OracleImplicitConnectionCache.java:1392)
    at oracle.jdbc.pool.OracleImplicitConnectionCacheThread.runAbandonedTimeout(OracleImplicitConnectionCacheThread.java:250)
    - locked <566080> (a oracle.jdbc.pool.OracleImplicitConnectionCache)
    at oracle.jdbc.pool.OracleImplicitConnectionCacheThread.run(OracleImplicitConnectionCacheThread.java:81)

此线程似乎负责关闭已放弃的连接,并且它本身被阻止等待其他线程完成:

"tomcat-http-8180-369" - Thread t@17665
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at oracle.net.ns.Packet.receive(Packet.java:282)
    at oracle.net.ns.DataPacket.receive(DataPacket.java:103)
    at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:230)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:175)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:100)
    at oracle.net.ns.NetInputStream.read(NetInputStream.java:85)
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:122)
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:78)
    at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readB1(T4CSocketInputStreamWrapper.java:149)
    at oracle.jdbc.driver.T4CMAREngine.buffer2Value(T4CMAREngine.java:2393)
    at oracle.jdbc.driver.T4CMAREngine.unmarshalSB8(T4CMAREngine.java:1401)
    at oracle.jdbc.driver.T4C8TTILob.readRPA(T4C8TTILob.java:837)
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:292)
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:186)
    at oracle.jdbc.driver.T4C8TTIClob.read(T4C8TTIClob.java:240)
    at oracle.jdbc.driver.T4CConnection.getChars(T4CConnection.java:3015)
    - locked <146da30> (a oracle.jdbc.driver.T4CConnection)
    at oracle.sql.CLOB.getChars(CLOB.java:402)
    at oracle.jdbc.driver.OracleClobReader.needChars(OracleClobReader.java:187)
    at oracle.jdbc.driver.OracleClobReader.read(OracleClobReader.java:142)
    at java.io.Reader.read(Reader.java:123)
    at oracle.jdbc.driver.ClobAccessor.getString(ClobAccessor.java:291)
    at oracle.jdbc.driver.T4CClobAccessor.getString(T4CClobAccessor.java:481)
    at oracle.jdbc.driver.OracleResultSetImpl.getString(OracleResultSetImpl.java:1251)
    - locked <146da30> (a oracle.jdbc.driver.T4CConnection)
    at oracle.jdbc.driver.OracleResultSet.getString(OracleResultSet.java:494)

这最后一个线程正在运行一个繁重的查询。这也是为什么它被认为是被放弃而且Tomcat试图关闭它的原因,但它似乎不能正在使用并且有锁定。

我不明白为什么:

  • Oracle无法关闭连接。
  • 在废弃连接关闭之前,其他线程无法从池中获取连接。

因为通过查看上面的线程堆栈,它发生了什么。当超长查询完成时(我知道我必须查看该查询)然后应用程序在线程解除阻塞后再次开始响应。

这是Tomcat的(v6)池配置(省略了敏感细节):

<Resource
        name="jdbc/MainDBPool"
        AutoCommit="true"
        defaultReadOnly="false"
        driverClassName="oracle.jdbc.OracleDriver"
        factory="oracle.jdbc.pool.OracleDataSourceFactory"
        fairQueue="false"
        initialSize="10"
        jdbcInterceptors="ConnectionState;StatementFinalizer"
        jmxEnabled="true"
        logAbandoned="false"
        maxActive="100"
        maxIdle="75"
        maxWait="30000"
        minEvictableIdleTimeMillis="5000"
        minIdle="10"
        removeAbandoned="true"
        removeAbandonedTimeout="60"
        testOnBorrow="false"
        testOnReturn="false"
        testWhileIdle="false"
        timeBetweenEvictionRunsMillis="5000"
        type="oracle.jdbc.pool.OracleDataSource"
        connectionCachingEnabled="true"
        connectionCacheName="tomcatConnectionCache1"
        fastConnectionFailoverEnabled="true"
        implicitCachingEnabled="true"
        connectionCacheProperties="(ValidateConnection=true, PropertyCheckInterval=60, AbandonedConnectionTimeout=300, InitialLimit=10, MinLimit=30, MaxLimit=200, ConnectionWaitTimeout=30, InactivityTimeout=300)"
        useEquals="false"
        validationInterval="30000"
        />

我还研究了其他可能的原因,比如一个很长的完整GC,但启用了GC记录,并且没有很长的停顿可以解释这一点。

提前致谢。

1 个答案:

答案 0 :(得分:0)

不支持Oracle隐式连接缓存。您必须使用通用连接池(UCP),它是ICC的替代品。您可以下载ucp.jar并查看"UCP with Tomcat"白皮书了解详情。