首先我们看一下Integer这个类,在使用它的时候非常非常的频繁,那我们看一下Integer有一个方法,叫valueOfpublic 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 propertyint 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_VALUEh = 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 cachereturn 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 executionfinal 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,把一个对象返回回来,@Overridepublic 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,是连接池的对象池,那这些都可以认为是享元模式的一个应用,非常容易理解,希望通过这个过程,对以后有类似的场景,我们就要考虑是否可以使用享元模式

享元模式源码解析(jdk+tomcat)相关推荐

  1. 代理模式源码解析(jdk+spring+mybatis)

    首先是java.lang.reflect,也就是我们刚刚使用的Proxy这个类,这里面coding的时候,也就是debug的时候,这个就是代理的一个典型应用,还有proxyFactoryBean,这个 ...

  2. 组合模式源码解析(jdk+mybatis)

    我们先看一下java.awt.container这么一个类,public class Container extends Component 我们可以看到这个类继承Component,awt这个包下边 ...

  3. 迭代器模式源码解析(jdk+mybatis)

    自己实现的数据结构,迭代器在源码中的一些应用,java.util.Iterator接口,/*** An iterator over a collection. {@code Iterator} tak ...

  4. 桥接模式源码解析(jdk)

    现在我们来看一下桥接模式在源码中的一些应用,首先我们说一下,我们先看一个接口,首先我们看一下Driver的实现类,我们看到com.mysql.jdbc实现了Driver,添加了ORACLE的驱动,或者 ...

  5. 源码解析 使用tomcat作为web容器时,用到的外观模式

    源码解析 使用tomcat作为web容器时,接收浏览器发送过来的请求, tomcat会将请求信息封装成ServletRequest对象, 如下图①处对象. 但是大家想想ServletRequest是一 ...

  6. 美团Leaf源码——号段模式源码解析

    前言 分布式ID生成策略基本要求就是全局不重复,最好还能递增,长度较短,性能高,可用性强.关于相关的实现方案有很多,本文着重使用美团开源的分布式ID生成解决方案--Leaf. 关于Leaf,美团官方的 ...

  7. Spark内核(上)——附:两种Yarn模式源码解析

    文章目录 一.Spark内核概述 1.1 Spark核心组件回顾 1.1.1 Driver 1.1.2 Executor 1.2 Spark通用运行流程概述 二.Spark通信架构概述 2.1 Spa ...

  8. 装饰者模式源码解析(spring-session mybatis jdk servlet)

    那在JDK中体现最明显的,就是JAVA IO方面的一些类,那在JAVA IO中,我们为了增加缓存,我们使用BufferedReader,那现在我们来看一下,那因为增加缓存的功能,类有很多,子类也就需要 ...

  9. 外观模式源码解析(springjdbc+myabtis+tomcat)

    我们首先看一下外观模式在SpringJDBC中的一些应用,我们看一下JdbcUtils,为了更好理解,把外观模式重新讲了一下,用积分的场景,我们直接继续看源码,这个是spring.jdbc包下的,这个 ...

最新文章

  1. 关闭webstorm自动保存,并显示文件未保存标识
  2. paper 89:视频图像去模糊常用处理方法
  3. javascript笔记——点击按钮(或超链接)如何跳转到另外一个页面并执行目标页面的js函数...
  4. java 700c corsa_JAVA CORSA休闲车,缔造“城市 生活 元素”
  5. python程序的基本结构知识点总结_Python知识点总结
  6. C# - 多线程(基础)
  7. dqn系列梳理_讲人话系列——DQN初探之2048
  8. 定时器计数器工作方式
  9. Python:如何安装与使用 pip
  10. 回顾2006年:网络通信十大事件
  11. Nuget包管理工具(程序包控制台执行语句)
  12. 彻底了解Cookie
  13. 仙人掌真的会防辐射吗
  14. vue 身份证格式校验
  15. iOS 直播技术及Demo
  16. C#几行代码实现定时关机/重启 超详细(建议新手练习)
  17. vue 设置滚动条的位置
  18. 7-40 奥运排行榜
  19. 链路层协议——SLIP协议和PPP协议
  20. 根据IP获取城市-新浪ip接口

热门文章

  1. 大数据正在改变汽车行业的5种方式
  2. Golang program to implement Binary Tree
  3. LINUX 如何实现多线程进行cp复制
  4. 前端学习 -- 颜色
  5. 08-Windows Server 2012 R2 会话远程桌面-标准部署-使用PowerShell进行部署2-1
  6. Linux下运行jar程序
  7. 那些年,我深爱着的PPT(一)
  8. [转载]-如何向妻子解释OOD
  9. 1.1 小巩的疑惑
  10. 耗尽您CPU资源的Explored病毒清除法