user2730428 user2730428 - 3 days ago 5
Java Question

Concurrent Modification when using connection pool

I am trying to get the jdbc connection using proxool connection pool in a Web application. Below code describes the same :

public static Connection getConnection(String key, boolean useConnectionPool, String poolName) {
Connection connection = null;
String alias = "DBCP" + poolName + "_" + key;
String driverClass = "com.mysql.jdbc.Driver";
checkAndLoadProps();
String driverUrl = "jdbc:mysql://" + props.getProperty(key + "_DBMS_URL") + "/" + props.getProperty(key + "_DEF_SCHEMA") + "?autoReconnect=true&useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=false&rewriteBatchedStatement=true";
String connectionPoolUrl = "proxool." + alias + ":" + driverClass + ":" + driverUrl;
try {
if (useConnectionPool) {
info.remove("user");
String user = props.getProperty(key + "_CLIENT");
info.setProperty("user", user);
info.remove("password");
String password = props.getProperty(key + "_CLIENT_PASS");
info.setProperty("password", password);
String host = props.getProperty(key + "_DBMS_URL");

synchronized (poolName) {
connection = DriverManager.getConnection(connectionPoolUrl, info);
}

}
if (connection != null) {
return connection;
} else {
System.out.println("DB Connection Not Established");
}

} catch (Exception ex) {
System.out.println("DB Connection Not Established::" + ex.getMessage());
ex.printStackTrace();
}
return null;
}


What happens is as soon as I start my server, more than 1 threads try to access this code parallely and it throws concurrent modification exception.

I understand it can be fixed by providing class level lock to the synchronized block. But it will severely affect the performance.

Any better solution to this?

Answer

For me your problem is more related to info which is obviously an instance of Properties that is shared. Knowing that Properties extends Hashtable and an Hashtable will throw a ConcurrentModificationException if you change its structure while iterating over it as stated into the javadoc:

if the Hashtable is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException.

And here if you have several threads calling this method in parallel they could concurrently remove properties which modifies the structure of your Hashtable and iterate over it within DriverManager.getConnection(connectionPoolUrl, info) which would end up with a ConcurrentModificationException.

What you should do is convert info into a ConcurrentHashMap<Object, Object> which is thread-safe and allows to be concurrently modified and iterated. Then you would provide as parameter to DriverManager.getConnection, a Properties instance created from info as next:

private static Map<Object, Object> info = new ConcurrentHashMap<>();

public static Connection getConnection(String key, boolean useConnectionPool, 
    String poolName) {

    ...
    Properties properties = new Properties();
    properties.putAll(info);
    connection = DriverManager.getConnection(connectionPoolUrl, properties);
Comments