Flyweight parsing source (jdk + tomcat)

首先我们看一下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,

是连接池的对象池,那这些都可以认为是享元模式的一个应用,非常容易理解,希望通过这个过程,对以后有类似的

场景,我们就要考虑是否可以使用享元模式

 

Guess you like

Origin blog.csdn.net/Leon_Jinhai_Sun/article/details/90901367