HikariCP源码解析一创建数据库连接池(二)

上篇介绍了HikariCP创建连接池的几种方式,跟踪源码发现其真正创建连接池是在HikariDataSource里的getConnection方法(即第一次获取连接则去创建连接池)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 private volatile HikariPool pool;
@Override
public Connection getConnection() throws SQLException{
if (isClosed()) {
throw new SQLException("HikariDataSource " + this + " has been closed.");
}

if (fastPathPool != null) {
return fastPathPool.getConnection();
}

// See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
HikariPool result = pool;
if (result == null) {
synchronized (this) {
result = pool;
if (result == null) {
validate();
LOGGER.info("{} - Starting...", getPoolName());
try {
pool = result = new HikariPool(this);
this.seal();
}
catch (PoolInitializationException pie) {
if (pie.getCause() instanceof SQLException) {
throw (SQLException) pie.getCause();
}
else {
throw pie;
}
}
LOGGER.info("{} - Start completed.", getPoolName());
}
}
}

return result.getConnection();
}

这里使用了双重检查机制,要注意的是pool变量使用了volatile这个关键字,原因是new一个对象并不是一个原子操作,要经过以下步骤:

  1. 给pool分配内存
  2. 调用构造函数初始化成员变量
  3. 将pool对象指向分配的内存(此步骤完成pool即为非空)

没有volatile关键字上面这3个步骤可能由于指令重排序令pool在多线程下未正确初始化即被使用则报错。volatile可禁止指令重排序,并强制本地线程去主存中读取pool变量。