设为首页 加入收藏

TOP

C3P0多数据源的死锁问题(一)
2014-11-24 00:04:55 来源: 作者: 【 】 浏览:35
Tags:C3P0 数据源 问题

最近在写的数据迁移工具完成的差不多了,今天将连接池换成C3P0,发现一个问题,就是配置了多个数据源的C3P0在同时获取不同数据源的Connection时会发生死锁。

1.运行如下的代码,用JProfiler测试,会发现死锁的情况:

代码:

package com.highgo.test.c3p0deadlock;

import java.sql.SQLException;

import com.mchange.v2.c3p0.ComboPooledDataSource;

//加锁source个postgre的ComboPooledDataSource的getConnection用一个锁
public class Test {

	public static void main(String[] args) throws InterruptedException {
		ComboPooledDataSource source = new ComboPooledDataSource("source");
		ComboPooledDataSource source2 = new ComboPooledDataSource("source");
		ComboPooledDataSource postgres = new ComboPooledDataSource("postgres");
		ComboPooledDataSource postgres2 = new ComboPooledDataSource("postgres");
		new Thread(new SourceGetConn(source), "source").start();
//		new Thread(new SourceGetConn(source2), "source2").start();
//		Thread.sleep(1000);
		new Thread(new DestGetConn(postgres), "postgres").start();
//		new Thread(new DestGetConn(postgres2), "postgres2").start();
	}

}

class SourceGetConn implements Runnable {

	private ComboPooledDataSource source = null;

	public SourceGetConn(ComboPooledDataSource source) {
		this.source = source;
	}

	@Override
	public void run() {
		while (true) {
			try {
				Thread.sleep(1000);
				source.getConnection();
				System.out.println("I get a Connection! I am in " + Thread.currentThread().getName());
			} catch (InterruptedException | SQLException e) {
				e.printStackTrace();
			}
		}
	}

}

class DestGetConn implements Runnable {

	private ComboPooledDataSource postgres = null;

	public DestGetConn(ComboPooledDataSource source) {
		this.postgres = source;
	}

	@Override
	public void run() {
		while (true) {
			try {
				Thread.sleep(1000);
				postgres.getConnection();
				System.out.println("I get a Connection! I am in " + Thread.currentThread().getName());
			} catch (InterruptedException | SQLException e) {
				e.printStackTrace();
			}
		}
	}

}

死锁情况: \

可以看到source和postgre两个进程都被一个没有记录的对象锁住了。

2.将上边的代码的Thread.sleep注释去掉,在运行,是不会有死锁问题的,于是查看C3P0的源代码,ComboPooledDataSource@getConnection是继承自AbstractPoolBackedDataSource#getConnection,代码如下:

public Connection getConnection() throws SQLException
    {
        PooledConnection pc = getPoolManager().getPool().checkoutPooledConnection();
        return pc.getConnection();
    }

    public Connection getConnection(String username, String password) throws SQLException
    { 
        PooledConnection pc = getPoolManager().getPool(username, password).checkoutPooledConnection();
        return pc.getConnection();
    }

先看这个PoolManager,AbstractPoolBackedDataSource#getPoolManager方法的实现如下,是线程安全的

 private synchronized C3P0PooledConnectionPoolManager getPoolManager() throws SQLException
    {
        if (poolManager == null)
        {
            ConnectionPoolDataSource cpds = assertCpds();
            poolManager = new C3P0PooledConnectionPoolManager(cpds, null, null, this.getNumHelperThreads(), this.getIdentityToken(), this.getDataSourceName());
            if (logger.isLoggable(MLevel.INFO))
                logger.info("Initializing c3p0 pool... " + this.toString( true )  /* + "; using pool manager: " + poolManager */);
        }
        return poolManager;	    
    }
从上边的代码也可以看出,一个DataSource实例,只保持一个PoolManager的引用。
再接着看
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇MonogDB-索引(三)GIS 下一篇nosql之redis高可用性集群方案,..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: