首先我们看一下Integer这个类,在使用它的时候非常非常的频繁,那我们看一下Integer有一个方法,叫valueOf
public final class Integer extends Number implements Comparable<Integer>
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
看一下里面的实现,首先做一个断言的判断,如果大于IntegerCache的最小值,并且小于等于IntegerCache的最大值,
我们直接从Cache里面获取,否则返回一个New出来的Integer对象,经常有一些Integer的判断,通过Integer的各种构造,
然后把构造出来的数字做等等判断,让你们判断这个结果是true还是false,那这种题也是比较常见,这里面就要对IntegerCache
了解,这段逻辑也非常清晰,也就是说如果走到return IntegerCache.cache[i + (-IntegerCache.low)];这里,这里并不是
new出来的IntegerCache对象,所以数字没有进入到if里面的时候,都是new出来的Integer对象,他们肯定不是同一个对象,
所以这个数字如果不在这个范围,==的时候一定是false,那很简单我们来测试一下
/**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* sun.misc.VM class.
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
IntegerCache这个类是一个private的静态内部类,最小值是-128,而high在静态块里边,声明了为127,也就是说如果我们
小于等于-128,大于等于127的话,不会在Cache里边,而这个high的值也是可以修改的,
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
我们看一下这一行,这里面从JVM的参数里面获取IntegerCache的最大值,然后再进行一些判断,非常容易理解,然后同理Long
类型里面也是有Cache的
private static class LongCache {
private LongCache(){}
static final Long cache[] = new Long[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Long(i - 128);
}
}
这里面也是有LongCache,我们再看一下他的valueOf方法呢
/**
* Returns a {@code Long} instance representing the specified
* {@code long} value.
* If a new {@code Long} instance is not required, this method
* should generally be used in preference to the constructor
* {@link #Long(long)}, as this method is likely to yield
* significantly better space and time performance by caching
* frequently requested values.
*
* Note that unlike the {@linkplain Integer#valueOf(int)
* corresponding method} in the {@code Integer} class, this method
* is <em>not</em> required to cache values within a particular
* range.
*
* @param l a long value.
* @return a {@code Long} instance representing {@code l}.
* @since 1.5
*/
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);
}
他的逻辑是类似的,说完这些我们再看一个,Tomcat提供的common连接池,我们打开这个类,GenericObjectPool,
这个很明显就是一个连接池,我们先看一下GenericObjectPoolConfig,连接池里默认的一些配置,也就是说如果这些数字
如果我们不配置的话,也会有,那他的实现很简单,我们随便找一个,GenericKeyedObjectPool,有两个版本,一个是pool2,
一个pool1,我们就看pool2的,那我们注意这个连接池,肯定有拿,肯定有放,我可以从这个连接池里界一个对象出来,
借过来我使用,使用完之后我还要放回去,我们看一个方法,borrowObject,
@Override
public T borrowObject(final K key) throws Exception {
return borrowObject(key, getMaxWaitMillis());
}
这里面又调用这个borrowObject(key, getMaxWaitMillis())方法,我们看一下,我们往下看一下,
public T borrowObject(final K key, final long borrowMaxWaitMillis) throws Exception {
assertOpen();
PooledObject<T> p = null;
// Get local copy of current config so it is consistent for entire
// method execution
final boolean blockWhenExhausted = getBlockWhenExhausted();
boolean create;
final long waitTime = System.currentTimeMillis();
final ObjectDeque<T> objectDeque = register(key);
try {
while (p == null) {
create = false;
p = objectDeque.getIdleObjects().pollFirst();
if (p == null) {
p = create(key);
if (p != null) {
create = true;
}
}
if (blockWhenExhausted) {
if (p == null) {
if (borrowMaxWaitMillis < 0) {
p = objectDeque.getIdleObjects().takeFirst();
} else {
p = objectDeque.getIdleObjects().pollFirst(
borrowMaxWaitMillis, TimeUnit.MILLISECONDS);
}
}
if (p == null) {
throw new NoSuchElementException(
"Timeout waiting for idle object");
}
} else {
if (p == null) {
throw new NoSuchElementException("Pool exhausted");
}
}
if (!p.allocate()) {
p = null;
}
if (p != null) {
try {
factory.activateObject(key, p);
} catch (final Exception e) {
try {
destroy(key, p, true);
} catch (final Exception e1) {
// Ignore - activation failure is more important
}
p = null;
if (create) {
final NoSuchElementException nsee = new NoSuchElementException(
"Unable to activate object");
nsee.initCause(e);
throw nsee;
}
}
if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
boolean validate = false;
Throwable validationThrowable = null;
try {
validate = factory.validateObject(key, p);
} catch (final Throwable t) {
PoolUtils.checkRethrow(t);
validationThrowable = t;
}
if (!validate) {
try {
destroy(key, p, true);
destroyedByBorrowValidationCount.incrementAndGet();
} catch (final Exception e) {
// Ignore - validation failure is more important
}
p = null;
if (create) {
final NoSuchElementException nsee = new NoSuchElementException(
"Unable to validate object");
nsee.initCause(validationThrowable);
throw nsee;
}
}
}
}
}
} finally {
deregister(key);
}
updateStatsBorrow(p, System.currentTimeMillis() - waitTime);
return p.getObject();
}
这里面通过ObjectDeque对象,一个双端队列,让他来保持对象池的对象,在最上面把这个连接池声明为一个空,
PooledObject<T> p = null;我们看一下下面怎么用,然后在try里面对他实际的使用,通过Object的双端队列,
来保存连接对象,当然这里还会调用一些factory的,factory.activateObject(key, p);存活着的对象,factory里面
有很多的方法,public interface KeyedPooledObjectFactory<K,V>,我们来看一下方法,有存活的对象activateObject,
有销毁的对象destroyObject,创建对象destroyObject,钝化对象passivateObject,校验对象validateObject,那很简单,
关注对象的几个状态,首先用这个池对象工厂来创建对象,那将不用的池对象进行钝化,对要使用的对象进行激活,
并且还要对池对象进行激活,把有问题的池对象进行销毁,那我们先回来继续来看,我们再来看一个方法returnObject,
把一个对象返回回来,
@Override
public void returnObject(final K key, final T obj) {
final ObjectDeque<T> objectDeque = poolMap.get(key);
final PooledObject<T> p = objectDeque.getAllObjects().get(new IdentityWrapper<>(obj));
if (p == null) {
throw new IllegalStateException(
"Returned object not currently part of this pool");
}
synchronized(p) {
final PooledObjectState state = p.getState();
if (state != PooledObjectState.ALLOCATED) {
throw new IllegalStateException(
"Object has already been returned to this pool or is invalid");
}
p.markReturning(); // Keep from being marked abandoned (once GKOP does this)
}
final long activeTime = p.getActiveTimeMillis();
try {
if (getTestOnReturn()) {
if (!factory.validateObject(key, p)) {
try {
destroy(key, p, true);
} catch (final Exception e) {
swallowException(e);
}
if (objectDeque.idleObjects.hasTakeWaiters()) {
try {
addObject(key);
} catch (final Exception e) {
swallowException(e);
}
}
return;
}
}
try {
factory.passivateObject(key, p);
} catch (final Exception e1) {
swallowException(e1);
try {
destroy(key, p, true);
} catch (final Exception e) {
swallowException(e);
}
if (objectDeque.idleObjects.hasTakeWaiters()) {
try {
addObject(key);
} catch (final Exception e) {
swallowException(e);
}
}
return;
}
if (!p.deallocate()) {
throw new IllegalStateException(
"Object has already been returned to this pool");
}
final int maxIdle = getMaxIdlePerKey();
final LinkedBlockingDeque<PooledObject<T>> idleObjects =
objectDeque.getIdleObjects();
if (isClosed() || maxIdle > -1 && maxIdle <= idleObjects.size()) {
try {
destroy(key, p, true);
} catch (final Exception e) {
swallowException(e);
}
} else {
if (getLifo()) {
idleObjects.addFirst(p);
} else {
idleObjects.addLast(p);
}
if (isClosed()) {
// Pool closed while object was being added to idle objects.
// Make sure the returned object is destroyed rather than left
// in the idle object pool (which would effectively be a leak)
clear(key);
}
}
} finally {
if (hasBorrowWaiters()) {
reuseCapacity();
}
updateStatsReturn(activeTime);
}
}
有一个poolMap,里面传了一个key,打开看一下
private final Map<K,ObjectDeque<T>> poolMap =
new ConcurrentHashMap<>();
poolMap它是一个ConcurrentHashMap,也就是说他折中了HashMap和Hashtable,使用ConcurrentHashMap,
来做这个连接池的Map,非常容易理解,也就是说在这个双端队列上一层,又包装了一层Map,也就是说呢poolMap,
是连接池的对象池,那这些都可以认为是享元模式的一个应用,非常容易理解,希望通过这个过程,对以后有类似的
场景,我们就要考虑是否可以使用享元模式