1.使用HashMap和lock机制
缺点是,在大量的加锁解锁过程中消耗性能
https://blog.csdn.net/shengxiaohua1/article/details/120702347
private Map<String, Connection> connectionPool = new HashMap<String, Connection>();
private ReentrantLock lock = new ReentrantLock();
public Connection getConnection(String key) {
try {
lock.lock();
if (connectionPool.containsKey(key)) {
return connectionPool.get(key);
} else {
//建立 Connection
Connection conn = createConnection();
connectionPool.put(key, conn);
return conn;
}
} finally {
lock.unlock();
}
}
//建立Connection
private Connection createConnection() {
return null;
}
上面的代码中HashMap可以替换成ConcurrentHashMap,这样可以不使用lock。但是这样又无法保证创建连接的原子性。产生了下面的方案:
2.使用ConcurrentHashMap和FutureTask作为线程池
ConcurrentHashMap和FutureTask都是线程安全的,故代码里没有额外加锁
//线程池
private ConcurrentHashMap<String, FutureTask> connectionPool = new ConcurrentHashMap<String, FutureTask>();
public Connection getConnection(String key) throws Exception {
FutureTask<Connection> connectionTask = connectionPool.get(key);
if (connectionTask != null) {
return connectionTask.get();
} else {
Callable<Connection> callable = new Callable<Connection>() {
@Override
public Connection call() throws Exception {
// TODO Auto-generated method stub
return createConnection();
}
};
FutureTask<Connection> newTask = new FutureTask<Connection>(callable);
//map中没有key就put,存在key就返回null
connectionTask = connectionPool.putIfAbsent(key, newTask);
if (connectionTask == null) {
connectionTask = newTask;
//FutureTask内部使用适配器模式,在run方法中调用了call方法
connectionTask.run();
}
//get等待run方法执行完返回结果
return connectionTask.get();
}
}
//建立Connection
private Connection createConnection() {
return null;
}
3.LinkedList + Semaphore
public class DBPoolSemaphore {
/**
* 池容量
*/
private final static int POOL_SIZE = 10;
/**
* useful 代表可用连接
* useless 代表已用连接
* 为什么要使用两个Semaphore呢?是因为,在连接池中不只有连接本身是资源,空位也是资源,也需要记录
*/
private final Semaphore useful, useless;
/**
* 连接池
*/
private final static LinkedList<Connection> POOL = new LinkedList<>();
/**
* 使用静态块初始化池
*/
static {
for (int i = 0; i < POOL_SIZE; i++) {
POOL.addLast(SqlConnection.fetchConnection());
}
}
public DBPoolSemaphore() {
// 初始可用的许可证等于池容量
useful = new Semaphore(POOL_SIZE);
// 初始不可用的许可证容量为0
useless = new Semaphore(0);
}
/**
* 获取数据库连接
*
* @return 连接对象
*/
public Connection takeConnection() throws InterruptedException {
// 可用许可证减一
useful.acquire();
Connection connection;
synchronized (POOL) {
connection = POOL.removeFirst();
}
// 不可用许可证数量加一
useless.release();
return connection;
}
/**
* 释放链接
*
* @param connection 连接对象
*/
public void returnConnection(Connection connection) throws InterruptedException {
if(null!=connection){
// 打印日志
System.out.println("当前有"+useful.getQueueLength()+"个线程等待获取连接,,"
+"可用连接有"+useful.availablePermits()+"个");
// 不可用许可证减一
useless.acquire();
synchronized (POOL){
POOL.addLast(connection);
}
// 可用许可证加一
useful.release();
}
}
}
4.java并发编程艺术208页
LinkedList + synchronized + Object.wait/Object.notify
public class ConnectionPool {
private LinkedList<Connection> pool = new LinkedList<Connection>();
public ConnectionPool(int initialSize) {
if (initialSize > 0) {
for (int i = 0; i < initialSize; i++) {
pool.addLast(ConnectionDriver.createConnection());
}
}
}
public void releaseConnection(Connection connection) {
if (connection != null) {
synchronized (pool) {
// 连接释放后需要进行通知,这样其他消费者能够感知到连接池中已经归还了一个连接
pool.addLast(connection);
pool.notifyAll();
}
}
}
// 在mills内无法获取到连接,将会返回null
public Connection fetchConnection(long mills) throws InterruptedException {
synchronized (pool) {
// 完全超时
if (mills <= 0) {
while (pool.isEmpty()) {
pool.wait();
}
return pool.removeFirst();
} else {
long future = System.currentTimeMillis() + mills;
long remaining = mills;
while (pool.isEmpty() && remaining > 0) {
pool.wait(remaining);
remaining = future - System.currentTimeMillis();
}
Connection result = null;
if (!pool.isEmpty()) {
result = pool.removeFirst();
}
return result;
}
}
}
}
总结
1、线程池需要一个保存所有线程的容器,可以选择HashMap,可以选择LinkedList等。
2、获取线程的时候由于存在竞争,所以需要枷锁lock或synchronized。
3、还需要监控池子中的容量,使用semaphore计数阻塞或Object.wait或LockSupport.park,总之当容量没有剩余的时候需要阻塞。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)