1.使用HashMap和lock机制
缺点是,在大量的加锁解锁过程中消耗性能
https://blog.csdn.net/shengxiaohua1/article/details/120702347
private MapconnectionPool = new HashMap (); 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 connectionPool = new ConcurrentHashMap();
public Connection getConnection(String key) throws Exception {
FutureTask connectionTask = connectionPool.get(key);
if (connectionTask != null) {
return connectionTask.get();
} else {
Callable callable = new Callable() {
@Override
public Connection call() throws Exception {
// TODO Auto-generated method stub
return createConnection();
}
};
FutureTask newTask = new FutureTask(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;
private final Semaphore useful, useless;
private final static LinkedList 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);
}
public Connection takeConnection() throws InterruptedException {
// 可用许可证减一
useful.acquire();
Connection connection;
synchronized (POOL) {
connection = POOL.removeFirst();
}
// 不可用许可证数量加一
useless.release();
return 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 pool = new LinkedList();
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,总之当容量没有剩余的时候需要阻塞。



