如何解决mysql驱动程序代码中的死锁问题?

时间:2018-02-06 19:01:48

标签: java mysql multithreading deadlock apache-commons-dbcp

如果我在性能环境中投入足够的流量,我可能会导致内存不足错误。如果我在此实例上执行线程转储,它将报告死锁:

Found one Java-level deadlock:
=============================
"http-nio-8080-exec-9":
  waiting to lock monitor 0x00007fb528003098 (object 0x00000000826d6018, a com.mysql.jdbc.LoadBalancedConnectionProxy),
  which is held by "Finalizer"
"Finalizer":
  waiting to lock monitor 0x00007fb528002fe8 (object 0x00000000826d5f98, a com.mysql.jdbc.ReplicationConnectionProxy),
  which is held by "http-nio-8080-exec-9"

我认为OOM正在发生,因为Finalizer已经死锁,无法收集未使用的实例。我不知道如何解决僵局问题。 http-nio-8080-exec-9线程正在这样做:

"http-nio-8080-exec-9":
    at com.mysql.jdbc.MultiHostConnectionProxy$JdbcInterfaceProxy.invoke(MultiHostConnectionProxy.java:104)
    - waiting to lock <0x00000000826d6018> (a com.mysql.jdbc.LoadBalancedConnectionProxy)
    at com.sun.proxy.$Proxy60.setPingTarget(Unknown Source)
    at com.mysql.jdbc.ReplicationConnectionProxy.invokeMore(ReplicationConnectionProxy.java:311)
    at com.mysql.jdbc.MultiHostConnectionProxy.invoke(MultiHostConnectionProxy.java:457)
    - locked <0x00000000826d5f98> (a com.mysql.jdbc.ReplicationConnectionProxy)
    at com.sun.proxy.$Proxy57.prepareStatement(Unknown Source)
    at org.apache.commons.dbcp2.DelegatingConnection.prepareStatement(DelegatingConnection.java:291)
    at org.apache.commons.dbcp2.DelegatingConnection.prepareStatement(DelegatingConnection.java:291)
   my code here

在我的代码的这一行,我的代码是这样做的:

preparedStatement = connect.prepareStatement(sqlQuery);

终结者线程正在这样做:

"Finalizer":
    at com.mysql.jdbc.ResultSetImpl.realClose(ResultSetImpl.java:6597)
    - waiting to lock <0x00000000826d5f98> (a com.mysql.jdbc.ReplicationConnectionProxy)
    at com.mysql.jdbc.ResultSetImpl.close(ResultSetImpl.java:851)
    at sun.reflect.GeneratedMethodAccessor112.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.mysql.jdbc.MultiHostConnectionProxy$JdbcInterfaceProxy.invoke(MultiHostConnectionProxy.java:108)
    - locked <0x00000000826d6018> (a com.mysql.jdbc.LoadBalancedConnectionProxy)
    at com.sun.proxy.$Proxy61.close(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor112.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.mysql.jdbc.MultiHostConnectionProxy$JdbcInterfaceProxy.invoke(MultiHostConnectionProxy.java:108)
    - locked <0x00000000826d6018> (a com.mysql.jdbc.LoadBalancedConnectionProxy)
    at com.sun.proxy.$Proxy62.close(Unknown Source)
    at org.apache.commons.dbcp2.DelegatingResultSet.close(DelegatingResultSet.java:169)
    at org.apache.commons.dbcp2.DelegatingStatement.close(DelegatingStatement.java:149)
    at org.apache.commons.dbcp2.DelegatingStatement.finalize(DelegatingStatement.java:549)
    at java.lang.System$2.invokeFinalize(System.java:1270)
    at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:98)
    at java.lang.ref.Finalizer.access$100(Finalizer.java:34)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:210)

ResultSetImpl.realClose在死锁时执行此操作:

synchronized (locallyScopedConn.getConnectionMutex()) {

两者似乎都与mysql jdbc驱动程序有关。我们正在使用org.apache.commons.dbcp2.BasicDataSource来建立连接池。这是我们建立连接的代码:

private static final BasicDataSource dataSource = new BasicDataSource();

private void setUpConnectionPool()
{
    final String JDBC_CONNECTION_STRING = System.getProperty("JDBC_CONNECTION_STRING");
    final String DB_USER_STRING = System.getProperty("DB_USER_STRING");
    final String DB_PASSWORD_STRING = System.getProperty("DB_PASSWORD_STRING");
    final int MAX_CONNECTIONS = System.getProperty("MAX_CONNECTIONS") == null  ? 100 : Integer.valueOf(System.getProperty("MAX_CONNECTIONS"));

    try {

        ReplicationDriver driver = new ReplicationDriver();
        dataSource.setUrl(JDBC_CONNECTION_STRING);
        dataSource.setDriver(driver);
        dataSource.setUsername(DB_USER_STRING);
        dataSource.setPassword(DB_PASSWORD_STRING);
        dataSource.setMaxTotal(MAX_CONNECTIONS);
        dataSource.setConnectionProperties("autoReconnect=true;roundRobinLoadBalance=true;");

    } catch (Exception e) {
        e.printStackTrace();
    }
}

初始化上下文时调用上述方法。然后,所有代码都通过调用此方法获得其连接:

public static Connection getConnection() throws SQLException {
    return dataSource.getConnection();
}

我希望这段代码有明显的错误,但是我没有看到它导致死锁的明显原因。

0 个答案:

没有答案