public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
注意:
Byte, Short, Long 缓存的范围都是 -128~127
Character 缓存的范围是 0~127
Integer的默认范围是 -128~127
最小值不能变
但最大值可以通过调整虚拟机参数 `
-Djava.lang.Integer.IntegerCache.high` 来改变
Boolean 缓存了 TRUE 和 FALS
2.2 String 串池
享元模式、不可变类。(详情见jvm第一天,内存结构文章对串池的记录)
2.3 BigDecimal BigInteger
享元模式、不可变类。(用AtomicReference<BigDecimal> ,保护BigDecimal ,是因为虽然BigDecimal 是线程安全的,单个方法是原子的,线程安全的,但是并不能保证多个方法的组合是线程安全的。其他不可变类也一样。)
3. DIY,自定义连接池
例如:一个线上商城应用,QPS 达到数千,如果每次都重新创建和关闭数据库连接,性能会受到极大影响。 这时预先创建好一批连接,放入连接池。一次请求到达后,从连接池获取连接,使用完毕后再还回连接池,这样既节约了连接的创建和关闭时间,也实现了连接的重用,不至于让庞大的连接数压垮数据库。
关于synchronized
使用synchronized对连接池上锁,如果没有空闲连接,当前线程调用连接池对象的wait方法,让线程进入waitSet,进入等待状态。因为CAS不断循环的操作适合于短时间运行的代码片段。CAS利用CPU不停的尝试获取锁,由于线程获取连接池以后,需要进行的操作比较多,耗时较多,此时CAS使用的CPU还在不断的空转,浪费CPU资源。所以让其进入等待状态可以节省CPu资源。
class Pool {
// 1. 连接池大小
private final int poolSize;
// 2. 连接对象数组
private Connection[] connections;
// 3. 连接状态数组 0 表示空闲, 1 表示繁忙
private AtomicIntegerArray states;
// 4. 构造方法初始化
public Pool(int poolSize) {
this.poolSize = poolSize;
this.connections = new Connection[poolSize];
this.states = new AtomicIntegerArray(new int[poolSize]);
for (int i = 0; i < poolSize; i++) {
connections[i] = new MockConnection("连接" + (i+1));
}
}
// 5. 借连接
public Connection borrow() {
while(true) {
for (int i = 0; i < poolSize; i++) {
// 获取空闲连接
if(states.get(i) == 0) {
if (states.compareAndSet(i, 0, 1)) {
log.debug("borrow {}", connections[i]);
return connections[i];
}
}
}
// 如果没有空闲连接,当前线程进入等待
synchronized (this) {
try {
log.debug("wait...");
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 6. 归还连接
public void free(Connection conn) {
for (int i = 0; i < poolSize; i++) {
if (connections[i] == conn) {
states.set(i, 0);
synchronized (this) {
log.debug("free {}", conn);
this.notifyAll();
}
break;
}
}
}
}
class MockConnection implements Connection {
// 实现略
}
以上实现没有考虑:
● 连接的动态增长与收缩
● 连接保活(可用性检测)
● 等待超时处理
● 分布式 hash
对于关系型数据库,有比较成熟的连接池实现,例如c3p0, druid等 对于更通用的对象池,可以考虑使用apache commons pool,例如redis连接池可以参考jedis中关于连接池的实现