Skip to content

Commit 4c63a7c

Browse files
authored
修改格式
1 parent 4574b0b commit 4c63a7c

1 file changed

Lines changed: 14 additions & 19 deletions

File tree

readMe.md

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -362,19 +362,18 @@ class RedisObject{
362362
如何设计一套合理的接口,将对象池本身逻辑抽象出来,这样实现其它的池化对象也相对简单清晰?
363363

364364
---
365-
下面就简单描述一下解决了哪些问题,和解决的思路:
366-
<li>1 替换所有String,体力活,要求是细心不出错,替换的时候还要重写hashcode,equal,parseInt等各种方法
367-
</br>
368-
<li>2 如何设计一套接口体系,首先设计AbstractPooledObject这个抽象类,然后声明好length(),size(),newInstance(),release(),等抽象方法;然后设计一个AbstractObjectPool这样的抽象类,这个抽象类主要实现对象池,它具有很多组不同大小的对象container,分配的时候就迅速定位到合适大小的container,释放的时候也一样;如果找不到合适大小的container或者说没有对象可以分配,那么就调用newInstance来分配新的对象;
369-
</br>
370-
<li>3 怎么设计策略?
371-
</br>
365+
下面就简单描述一下解决了哪些问题,和解决的思路:
366+
<li>1 替换所有String,体力活,要求是细心不出错,替换的时候还要重写hashcode,equal,parseInt等各种方法
367+
<li>2 如何设计一套接口体系,首先设计AbstractPooledObject这个抽象类,然后声明好length(),size(),newInstance(),release(),等抽象方法;然后设计一个AbstractObjectPool这样的抽象类,这个抽象类主要实现对象池,它具有很多组不同大小的对象container,分配的时候就迅速定位到合适大小的container,释放的时候也一样;如果找不到合适大小的container或者说没有对象可以分配,那么就调用newInstance来分配新的对象;
368+
369+
<li>3 怎么设计策略?
370+
372371
```
373372
首先我们将对象池理解为一个管道,一边是流入的对象(release),一边是流出(allocate),那么我们取一段时间之内这两者的调和平均数作为对象池的大小,就可以比较好的适应需求; 所以需要进行统计,每次allocate的时候对申请对应大小的数组位置+1,release的时候也对对应大小的数组的位置+1; 这样就相当于统计一段时间之内分配次数和释放次数;
374-
我们考虑这样一种情况: 将JavaRedis作为一个分布式的锁的实现,也就是set一下然后很快就释放掉;这种情况下中间有一个时间差delay,可以想到在delay结束之前,是不会有release被调用的,但是只要过了这个delay,那么就有数据被释放了,中间阶段都会达成一个平衡的状态;大概像下面一样:
375-
allocate allocate ..................... allocate ........ allocate...
376-
[------ delay(3s)--------] release release ..... release ......
377-
当然中间可能存在一些波动,比如delay变化了,或者一段时间没有收到这样情况的请求;
373+
我们考虑这样一种情况: 将JavaRedis作为一个分布式的锁的实现,也就是set一下然后很快就释放掉;这种情况下中间有一个时间差delay,可以想到在delay结束之前,是不会有release被调用的,但是只要过了这个delay,那么就有数据被释放了,中间阶段都会达成一个平衡的状态;大概像下面一样:
374+
<li>allocate allocate ..................... allocate ........ allocate...
375+
<li>[------ delay(3s)--------] release release ..... release ......
376+
当然中间可能存在一些波动,比如delay变化了,或者一段时间没有收到这样情况的请求;
378377
所以需要将统计的时间稍微扩大一点,变化平缓一点: 所以把这个数据当成一个时间序列我们进行加权:
379378
380379
allocateAccumulation[index] = allocateAccumulation[index] * scaleDown + allocateArray[index]
@@ -387,8 +386,7 @@ releaseAccumulation[index] = releaseAccumulation[index] * scaleDown + releaseArr
387386
```
388387

389388
<li>4 怎么迅速定位?
390-
我们将设计对象池的长度为一系列长度 s1,s2,s3....sn,然后在中间插入 一些 2^n大小的数据,这样给定一个len,就利用JDK里面的办法先定位到第一个大于len的2^k,然后往回找一下,看哪个是第一个大于len且在我们初始化好的lengthTable里面,返回对应的index即可; 如果该池没有启用或者没有合适对象,可以尝试去更大的对象池找一下,但是不得超过所需的两倍大小;
391-
389+
我们将设计对象池的长度为一系列长度 s1,s2,s3....sn,然后在中间插入 一些 2^n大小的数据,这样给定一个len,就利用JDK里面的办法先定位到第一个大于len的2^k,然后往回找一下,看哪个是第一个大于len且在我们初始化好的lengthTable里面,返回对应的index即可; 如果该池没有启用或者没有合适对象,可以尝试去更大的对象池找一下,但是不得超过所需的两倍大小;
392390
释放的时候也是一样的策略,关键是找到一个合适的长度s,使得 s <= len(注意这里和分配的要求恰恰相反,可以思考下为什么),
393391
然后尝试将数据返回对应的容器,如果满了就算了;
394392

@@ -400,7 +398,7 @@ releaseAccumulation[index] = releaseAccumulation[index] * scaleDown + releaseArr
400398

401399

402400
<li>6 怎么保证一个线程里面release的时候是安全的?
403-
首先明确问题是什么: 假设我有一个key(RedisString),这个key在什么时候应该被释放呢? 有这些场景:
401+
首先明确问题是什么: 假设我有一个key(RedisString),这个key在什么时候应该被释放呢? 有这些场景:
404402
1 get请求,只读请求,显然可以释放
405403
2 set请求,如果这个ke已经重复了,那么可以直接释放,同时还可以释放老的value
406404
难点在于: 我们如何保证这个RedisString释放的时候下面没有使用了? 比如如果现在处于 rehash的状态,那么
@@ -409,11 +407,8 @@ releaseAccumulation[index] = releaseAccumulation[index] * scaleDown + releaseArr
409407
总结一下 Command -> RedisDb -> RedisDict -> RedisConcurrentHashMap -> RedisHashMap
410408
-> RedisHashMap
411409
ExpireHelper -> RedisDict也使用到了对应的调用链
412-
我们要找到一个合适的位置释放该释放的东西,避免提前释放的错误;
413-
</br>
414-
415-
目前暂时先手动把逻辑写对,但是最好的做法将所有的释放集中到一个层面来管理:
416-
</br>
410+
我们要找到一个合适的位置释放该释放的东西,避免提前释放的错误;
411+
目前暂时先手动把逻辑写对,但是最好的做法将所有的释放集中到一个层面来管理:
417412
```
418413
* 1 所有从CommnadHandler里面传入的key和value,我们设置一个isUsed的标记,如果这个key没有被使用过
419414
* 那么就直接在RedisDb这个api的层面就进行释放;如果被使用了那么就不进行释放

0 commit comments

Comments
 (0)