文章目录
Jedis线程池的代码编写,也是基于池化技术的基础上的,只不过这里的对象池化中的对象,变成了线程罢了。
preparePool()池子准备
public void preparePool() throws Exception {
//如果最小空闲数设置为大于等于1的话
if (this.getMinIdle() >= 1) {
//那么就需要保证最小空闲对象数
this.ensureMinIdle();
}
}
转到ensureMinIdle()
方法
void ensureMinIdle() throws Exception {
//这里面是一个方法重载,输入参数为:要求的最小空闲数,always=true
this.ensureIdle(this.getMinIdle(), true);
}
转到this.ensureIdle(this.getMinIdle(), true)
方法
private void ensureIdle(int idleCount, boolean always) throws Exception {
//映入眼帘的是一个相当长的判断
//只有满足下述的判断,才会进行后续操作,否则无动作
//idleCount为我们传入的参数this.getMinIdle(),即我们设置的最小空闲数,要满足大于等于1的要求,算是一个重复判断,前面我们已经判断过一次了
//并且!this.isClosed(),线程池不为关闭的状态
//always我们已经传入为true了
if (idleCount >= 1 && !this.isClosed() &&
(always || this.idleObjects.hasTakeWaiters())) {
//当idleObjects里的对象数量小于最小空闲要求的时候,进行处理
//我们知道idleObjects是一个阻塞双向队列,里面有个全局锁
//该队列里面存放的是空闲对象
while(this.idleObjects.size() < idleCount) {
//将要去创造出一个空闲对象,可能不会成功,因为超出设定的总数也是有可能的
PooledObject<T> p = this.create();
if (p == null) {
break;
}
//判断是否是后进先出
if (this.getLifo()) {
//是的话,则将对象加到队首
this.idleObjects.addFirst(p);
} else {
//否则,则将对象加到队尾
this.idleObjects.addLast(p);
}
}
if (this.isClosed()) {
//如果这个时候检测到关闭
//则进行清空操作
//这样看来,这个this.isClosed()也是有一定的滞后性的
this.clear();
}
}
}
看了这几处代码,我们可以很清晰的觉察出preparePool()是什么情况,逻辑是这样的:先去判断设置的MinIdle数,就是池子里最小要保持的空闲对象数量,如果池子没满,并且空闲数量不足,那么就会去创建对象。
create()创造对象
private PooledObject<T> create() throws Exception {
//localMaxTotal如果个人自定义没有设置的话,是-1
int localMaxTotal = this.getMaxTotal();
//意思就是说,如果没有对localMaxTotal进行设置,那么就不设置池子的上限,上限默认为Integer.MAX_VALUE
if (localMaxTotal < 0) {
localMaxTotal = 2147483647;
}
Boolean create = null;
while(create == null) {
//synchronized是对makeObjectCountLock对象上锁啊
//初始化的时候makeObjectCountLock=new Object,只是为了对象头里的锁,该对象无意义
synchronized(this.makeObjectCountLock) {
//createCount是一个原子long型数,先新增一个
long newCreateCount = this.createCount.incrementAndGet();
//如果这个新增后的数,超过了设定的池子的最大容量
if (newCreateCount > (long)localMaxTotal) {
//改回去,不新增了
this.createCount.decrementAndGet();
//瞅瞅makeObjectCount那边还有没有剩余的容量
if (this.makeObjectCount == 0L) {
//makeObjectCount为0,那就铁定生成不了新的对象了,早点散了吧,create设置为false
create = Boolean.FALSE;
} else {
//等呗,等待makeObjectCountLock释放锁,再来一遍这个while循环
this.makeObjectCountLock.wait();
}
} else {
//makeObjectCount增加1,这个意思就是在造途中的对象数量啊
++this.makeObjectCount;
//可以建造新对象
create = Boolean.TRUE;
}
}
}
if (!create) {
//false,就是不能造新对象
return null;
} else {
//可以造新对象
boolean var16 = false;
PooledObject p;
try {
var16 = true;
//传入的工厂类制造新对象
p = this.factory.makeObject();
var16 = false;
} catch (Exception var19) {
this.createCount.decrementAndGet();
throw var19;
} finally {
if (var16) {
//var16==true只有可能是工厂类制造对象的时候报错了
synchronized(this.makeObjectCountLock) {
//所以将makeObjectCount-1
--this.makeObjectCount;
//通知所有等待的线程
this.makeObjectCountLock.notifyAll();
}
}
}
//制造对象完毕,那么在途制造数也是要减1的
synchronized(this.makeObjectCountLock) {
--this.makeObjectCount;
//通知所有的对象
this.makeObjectCountLock.notifyAll();
}
AbandonedConfig ac = this.abandonedConfig;
//判断AbandonedConfig里的logAbandoned属性
if (ac != null && ac.getLogAbandoned()) {
p.setLogAbandoned(true);
}
//已经被创造的对象数量+1
this.createdCount.incrementAndGet();
//对象Map名册里加入这个新创造的对象
this.allObjects.put(new IdentityWrapper(p.getObject()), p);
//返回对象
return p;
}
}
addObject()添加对象到队列
public void addObject() throws Exception {
//确认对象池没有关闭,如果关闭了的话,就会抛出异常来
this.assertOpen();
//需要判断构造对象的工厂类是否不为空
if (this.factory == null) {
//构造对象的工厂类为空,则抛出异常
throw new IllegalStateException("Cannot add objects without a factory.");
} else {
//构造新对象,create我们已经解析过了,如果不满足构造条件,也会抛出异常来
PooledObject<T> p = this.create();
//插入空闲对象队列
this.addIdleObject(p);
}
}
看下具体是怎么插入的,除了判断是否后进先出之外,还调用了passivateObject
方法,看了一下,这个是需要实现对象继承编写的方法,返回void,如果判断不通过,直接抛出异常。
private void addIdleObject(PooledObject<T> p) throws Exception {
if (p != null) {
this.factory.passivateObject(p);
if (this.getLifo()) {
this.idleObjects.addFirst(p);
} else {
this.idleObjects.addLast(p);
}
}
}
borrowObject()借一个对象?对象还能借的?借了是不是要还回去?
public T borrowObject() throws Exception {
//调用了一个重载方法,传入参数为最大等待时长
return this.borrowObject(this.getMaxWaitMillis());
}
我们逐行来分析borrowObject方法
public T borrowObject(long borrowMaxWaitMillis) throws Exception {
//确认线程池现在是开启状态
this.assertOpen();
AbandonedConfig ac = this.abandonedConfig;
//是否移除销毁很久不被使用的对象,这串代码就是做这个判断,并且执行移除、销毁的操作
if (ac != null && ac.getRemoveAbandonedOnBorrow() && this.getNumIdle() < 2 && this.getNumActive() > this.getMaxTotal() - 3) {
this.removeAbandoned(ac);
}
PooledObject<T> p = null;
//资源耗尽是否阻塞
boolean blockWhenExhausted = this.getBlockWhenExhausted();
//当前时间
long waitTime = System.currentTimeMillis();
//自循环,需要里面的跳出来,才能解除循环
while(true) {
boolean create;
do {
do {
do {
//如果对象已经得到那么就返回对象,顺便更新下对象借用情况
if (p != null) {
this.updateStatsBorrow(p, System.currentTimeMillis() - waitTime);
return p.getObject();
}
create = false;
//从空闲对象队列里取出队首的对象
p = (PooledObject)this.idleObjects.pollFirst();
if (p == null) {
//如果空闲队列为空,则创造一个
p = this.create();
if (p != null) {
//创造成功,说明这个对象是新增的
create = true;
}
}
//当资源枯竭的时候,则阻塞
if (blockWhenExhausted) {
if (p == null) {
//这个默认是-1啊,借用对象最大等待时间
if (borrowMaxWaitMillis < 0L) {
//不等了,直接拿
p = (PooledObject)this.idleObjects.takeFirst();
} else {
p = (PooledObject)this.idleObjects.pollFirst(borrowMaxWaitMillis, TimeUnit.MILLISECONDS);
}
}
if (p == null) {
//如果还是没有得到对象,那么就报错:获取空闲对象超时
throw new NoSuchElementException("Timeout waiting for idle object");
}
} else if (p == null) {
throw new NoSuchElementException("Pool exhausted");
}
//我们总结一下,如何拿到PooledObject,首先去idleList拿,如果拿不到,则新建,如果新建不成,那就抛异常
//拿到了之后,我们还需要判断PooledObject的状态,这里将是一个很重要的判断点,我们待会说
if (!p.allocate()) {
p = null;
}
} while(p == null);
try {
//活化该对象
this.factory.activateObject(p);
} catch (Exception var13) {
try {
//活化失败,则销毁该对象
this.destroy(p);
} catch (Exception var12) {
}
p = null;
if (create) {
//如果这个对象是新建出来的,则抛出无法活化该对象的异常
NoSuchElementException nsee = new NoSuchElementException("Unable to activate object");
nsee.initCause(var13);
throw nsee;
}
}
} while(p == null);
} while(!this.getTestOnBorrow() && (!create || !this.getTestOnCreate()));
//认证设为false
boolean validate = false;
//认证异常,初始化为空
Throwable validationThrowable = null;
try {
//验证对象的可用性,比如jedis是调用JRedis对象的ping()方法
validate = this.factory.validateObject(p);
} catch (Throwable var15) {
PoolUtils.checkRethrow(var15);
validationThrowable = var15;
}
if (!validate) {
//如果验证不通过
try {
//销毁该对象
this.destroy(p);
//在借用对象的过程中因为验证不通过而毁掉的对象数量+1
this.destroyedByBorrowValidationCount.incrementAndGet();
} catch (Exception var14) {
}
p = null;
if (create) {
//其实是新建成功一个对象了的,但是最后因为没有验证通过,所以这个对象新建失败
NoSuchElementException nsee = new NoSuchElementException("Unable to validate object");
nsee.initCause(validationThrowable);
throw nsee;
}
}
}
}
我们理一下逻辑,借用object,也是先问空闲队列借,借不到了才去创建,而且需要判断创建是否阻塞,以及传递阻塞最长时间,后面还需要用工厂里的验证方法验证该对象。
不过需要注意的是,其中的一个判断,p.allocate()
判断该对象是否已经allocate
public synchronized boolean allocate() {
//只有该池化对象的状态为IDLE的前提下,才会返回true
if (this.state == PooledObjectState.IDLE) {
//将该对象的状态改为allocated,被放置
this.state = PooledObjectState.ALLOCATED;
//修改该对象上一次借用时间
this.lastBorrowTime = System.currentTimeMillis();
//修改该对象上一次使用时间,看起来,对象被借用了,默认对象被使用了
this.lastUseTime = this.lastBorrowTime;
//被借用的对象计数+1
++this.borrowedCount;
if (this.logAbandoned) {
//如果设置日志抛出的话,调用快照
this.borrowedBy.fillInStackTrace();
}
return true;
} else if (this.state == PooledObjectState.EVICTION) {
//如果该对象是在EVICTION(被淘汰)状态的时候,则将状态改为EVICTION_RETURN_TO_HEAD(被淘汰的重新回来到队列头部?)
this.state = PooledObjectState.EVICTION_RETURN_TO_HEAD;
return false;
} else {
return false;
}
}
returnObject()有借得有还,我们看下返回代码
public void returnObject(T obj) {
//查询一下,这个对象是否在全部对象Map表里
PooledObject<T> p = (PooledObject)this.allObjects.get(new IdentityWrapper(obj));
if (p == null) {
//如果不在,那么报错,归还的对象本身不在这个对象池里,那就无法归还该对
if (!this.isAbandonedConfig()) {
throw new IllegalStateException("Returned object not currently part of this pool");
}
} else {
synchronized(p) {
//对该对象进行上锁,拿到锁了之后,查询状态
PooledObjectState state = p.getState();
//如果对象不是已放置(allocated)状态的话,那就返回不了对象池
if (state != PooledObjectState.ALLOCATED) {
throw new IllegalStateException("Object has already been returned to this pool or is invalid");
}
//将对象状态改为RETURNING
p.markReturning();
}
//对象激活时间
long activeTime = p.getActiveTimeMillis();
//判断对象回归对象池是否也要进行测试,以及测试结果
if (this.getTestOnReturn() && !this.factory.validateObject(p)) {
//测试结果失败,销毁对象
try {
this.destroy(p);
} catch (Exception var10) {
this.swallowException(var10);
}
//因为返回的对象失败了,所以尝试新造一个对象补给对象池
try {
this.ensureIdle(1, false);
} catch (Exception var9) {
this.swallowException(var9);
}
//返回对象计数+1
this.updateStatsReturn(activeTime);
} else {
try {
//活化对象
this.factory.passivateObject(p);
} catch (Exception var12) {
//如果活化失败,那么吞掉这个异常,重新创建一个对象出来补上
this.swallowException(var12);
try {
this.destroy(p);
} catch (Exception var8) {
this.swallowException(var8);
}
try {
this.ensureIdle(1, false);
} catch (Exception var7) {
this.swallowException(var7);
}
this.updateStatsReturn(activeTime);
return;
}
//将locate状态、returing状态的对象改为idle状态的对象
if (!p.deallocate()) {
//失败,抛出异常,要么这个对象已经回归对象池了,要么该对象失效了
throw new IllegalStateException("Object has already been returned to this pool or is invalid");
} else {
//获取最大空闲数
int maxIdleSave = this.getMaxIdle();
if (this.isClosed() || maxIdleSave > -1 && maxIdleSave <= this.idleObjects.size()) {
//如果对象池已经关闭,最大空闲数大于-1,并且小于等于目前空闲队列的对象数
try {
//则销毁对象
this.destroy(p);
} catch (Exception var11) {
this.swallowException(var11);
}
} else {
//否则将对象返回空闲队列,根据是否Lifo
if (this.getLifo()) {
this.idleObjects.addFirst(p);
} else {
this.idleObjects.addLast(p);
}
if (this.isClosed()) {
this.clear();
}
}
this.updateStatsReturn(activeTime);
}
}
}
}
获取当前活跃对象数量
public int getNumActive() {
//总的对象数量-空闲队列数量
return this.allObjects.size() - this.idleObjects.size();
}
use(T pooledObject)使用对象
public void use(T pooledObject) {
AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getUseUsageTracking()) {
PooledObject<T> wrapper = (PooledObject)this.allObjects.get(new IdentityWrapper(pooledObject));
//调用对象的use方法。。。
wrapper.use();
}
}
close()关闭对象池
public void close() {
if (!this.isClosed()) {
synchronized(this.closeLock) {
if (!this.isClosed()) {
//这里会开启evict
this.startEvictor(-1L);
this.closed = true;
this.clear();
this.jmxUnregister();
this.idleObjects.interuptTakeWaiters();
}
}
}
}
evict()驱逐?逐出?这么暴力的么,我们看看咋回事
参考
原来是叫淘汰机制啊,eviction policy原来是这么回事。
public void evict() throws Exception {
//老规矩,先看看线程池有没有开放,没有开放直接抛异常
this.assertOpen();
if (this.idleObjects.size() > 0) {
//如果空闲队列有空闲对象
PooledObject<T> underTest = null;
//淘汰机制
EvictionPolicy<T> evictionPolicy = this.getEvictionPolicy();
//evictionLock对象锁,就跟那个makeCountLock差不多类型的,就是new 一个object
synchronized(this.evictionLock) {
//构造淘汰机制config
EvictionConfig evictionConfig = new EvictionConfig(this.getMinEvictableIdleTimeMillis(), this.getSoftMinEvictableIdleTimeMillis(), this.getMinIdle());
//默认是false
boolean testWhileIdle = this.getTestWhileIdle();
int i = 0;
//int numTestsPerEvictionRun = this.getNumTestsPerEvictionRun();默认值为3
//return numTestsPerEvictionRun >= 0 ? Math.min(numTestsPerEvictionRun, this.idleObjects.size()) : (int)Math.ceil((double)this.idleObjects.size() / Math.abs((double)numTestsPerEvictionRun));
//如果numTestsPerEvictionRun>=0,那么就取空闲队列的数量与这个设定值的最小值,如果小于0,则取空闲队列数量/numTestsPerEvictionRun,向上取整
int m = this.getNumTests();
//开启一个死循环
while(true) {
//当所有对象全都被destry后,才会跳出该循环
if (i >= m) {
break;
}
if (this.evictionIterator == null || !this.evictionIterator.hasNext()) {
this.evictionIterator = new EvictionIterator(this, this.idleObjects);
}
if (!this.evictionIterator.hasNext()) {
return;
}
label81: {
try {
underTest = this.evictionIterator.next();
} catch (NoSuchElementException var15) {
--i;
this.evictionIterator = null;
break label81;
}
//如果该对象的状态为PooledObjectState.IDLE,则将状态改为EVICTION并返回true,如果不是的话,则返回false
if (!underTest.startEvictionTest()) {
--i;
} else {
boolean evict;
try {
//判断最小空闲数是否小于空闲队列对象数,并且,该对象的空闲时间是否超过设定的空闲软抛弃时间,或者空闲时间是否超过空闲抛弃时间
evict = evictionPolicy.evict(evictionConfig, underTest, this.idleObjects.size());
} catch (Throwable var14) {
PoolUtils.checkRethrow(var14);
this.swallowException(new Exception(var14));
evict = false;
}
if (evict) {
//通过判断,则摧毁该对象
this.destroy(underTest);
//经过淘汰策略毁灭对象的计数+1
this.destroyedByEvictorCount.incrementAndGet();
} else {
if (testWhileIdle) {
boolean active = false;
try {
//活化该对象
this.factory.activateObject(underTest);
active = true;
} catch (Exception var13) {
this.destroy(underTest);
//活化失败可以直接将之除名
//经过淘汰策略毁灭对象的计数+1
this.destroyedByEvictorCount.incrementAndGet();
}
if (active) {
if (!this.factory.validateObject(underTest)) {
this.destroy(underTest);
this.destroyedByEvictorCount.incrementAndGet();
} else {
try {
this.factory.passivateObject(underTest);
} catch (Exception var12) {
this.destroy(underTest);
this.destroyedByEvictorCount.incrementAndGet();
}
}
}
}
if (!underTest.endEvictionTest(this.idleObjects)) {
}
}
}
}
++i;
}
}
}
//移除抛出的配置
AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
this.removeAbandoned(ac);
}
}
envict方法,就是要把所有的对象都淘汰掉。目标,对全部对象调用destroy方法
总结
至此我们将Pool池化技术里的准备池子,创造对象,新增对象,借用对象,返还对象,使用对象,清空对象,淘汰毁灭对象,关闭池子,这几个动作都解析了一遍。
其实挺简单的,就是维护一个阻塞双端队列,用来存放空闲对象,以及维护一个concurrentMap,用来存放池子里的所有对象。
以及池子里对象的状态的各种变化。
public enum PooledObjectState {
//空闲状态
IDLE,
//被使用的状态
ALLOCATED,
//被淘汰的状态
EVICTION,
//被标记淘汰但是又把它搞回来了
EVICTION_RETURN_TO_HEAD,
//认证状态
VALIDATION,
//被使用前的认证状态
VALIDATION_PREALLOCATED,
//认证完返回空闲队列前的状态
VALIDATION_RETURN_TO_HEAD,
//该对象失效
INVALID,
//被遗弃
ABANDONED,
//返回池子的过程中
RETURNING;
private PooledObjectState() {
}
}
下一章我们将简单聊一聊,Jedis对池化技术的使用,具体是怎么变成线程池的。