一个线上商城应用,QPS 达到数千,如果每次都重新创建和关闭数据库连接,性能会受到极大影响。 这时 预先创建好一批连接,放入连接池。一次请求到达后,从连接池获取连接,使用完毕后再还回连接池,这样既节约 了连接的创建和关闭时间,也实现了连接的重用,不至于让庞大的连接数压垮数据库
package ConnectedPool;
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicIntegerArray;
public class Pool {
//连接池大小 现在只实现不支持扩容的
private final int pollSize;
//连接池数组
private Connection[] connections;
//连接状态数组 0表示空闲 1表示繁忙 不能用int数组 因为多线程改变数组线程不能
//把锁加载了线程池数组的每个元素上 比加在整个线程池上更优
private AtomicIntegerArray states;
//构造方法
public Pool(int pollSize) {
this.pollSize = pollSize;
this.connections = new Connection[pollSize];
this.states = new AtomicIntegerArray(new int[pollSize]);
for(int i = 0; i<pollSize; i++){
connections[i] = new MockConnection();
}
}
//借连接
public Connection borrow(){
//使用cas
while (true){
for(int i = 0; i<pollSize; i++){
if (states.get(i) == 0) {
//cas
if (states.compareAndSet(1,0,1)) {
return connections[i];
}
}
}
//如果没有空闲连接 那么让当前线程进入等待
//防止cas的一直空转
synchronized (this){
try {
//等待
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//归还连接
public void free(Connection connection){
for(int i = 0; i<pollSize; i++){
if(connections[i] == connection){
//这里因为归还的时候 我本身就这个connection的持有者
//也就只有我会对这个数组的这个位置进行改变
//没有其他和我竞争 所以不用锁
states.set(i,0);
//唤醒
synchronized (this){
this.notifyAll();
}
break;
}
}
}
//模拟一个连接创建
class MockConnection implements Connection{
.......
}
public static void main(String[] args) {
Pool pool = new Pool(2);
for (int i = 0; i < 5; i++) {
new Thread(()->{
Connection conn = pool.borrow();
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
pool.free(conn);
}
}).start();
}
}
}
以上实现没有考虑:
- 连接的动态增长与收缩
- 连接保活(可用性检测)
- 等待超时处理
- 分布式 hash