版权声明:本文为博主原创文章,转载去请注明出处
AbstractReferenceCountedByteBuf源码分析
成员变量,其中对引用计数的解释是如果引用计数为奇数,则对应的实际引用计数为0,如果为偶数,则对应的实际引用计数为无符号右移一位所对应的值,且引用计数变量用volatile修饰,意味着当一个线程对该值进行修改后会立刻写回内存中。REFCNT_FIELD_OFFSET变量用于标识refCnt字段在AbstractReferenceCountedByteBuf中的内存地址。
private static final long REFCNT_FIELD_OFFSET;
private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> refCntUpdater =
AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt");
// even => "real" refcount is (refCnt >>> 1); odd => "real" refcount is 0
@SuppressWarnings("unused")
private volatile int refCnt = 2;//对象的引用计数
此方法返回真实的引用计数
private static int realRefCnt(int rawCnt) {
return (rawCnt & 1) != 0 ? 0 : rawCnt >>> 1;
}
增加引用计数值的方法,最后都会调用如下这个函数。首先对传入的真实的引用计数值左移一位,变为原值的两倍,此处发生溢出错误也没问题,在后面会进行判断。然后通过原子操作将当前修改的计数值更新到refCnt中,并返回refCnt上一次的值,判断,如果上一个refCnt的值为奇数,抛出引用计数异常(因为此时可能已经有另一个线程对该对象引用计数减一使得该对象被释放了);再判断是否发生了溢出异常,如果发生之后需要先把refCnt的值减去之前增加的值,然后抛出异常;最后返回当前对象
private ByteBuf retain0(final int increment) {
// all changes to the raw count are 2x the "real" change
int adjustedIncrement = increment << 1; // overflow OK here
int oldRef = refCntUpdater.getAndAdd(this, adjustedIncrement);
if ((oldRef & 1) != 0) {
throw new IllegalReferenceCountException(0, increment);
}
// don't pass 0!
if ((oldRef <= 0 && oldRef + adjustedIncrement >= 0)
|| (oldRef >= 0 && oldRef + adjustedIncrement < oldRef)) {
// overflow case
refCntUpdater.getAndAdd(this, -adjustedIncrement);
throw new IllegalReferenceCountException(realRefCnt(oldRef), increment);
}
return this;
}
这里getAndAdd方法使用了一个自旋锁,首先取得在内存中传入对象obj相应字段的值,调用compareAndSet方法,传入当前对象obj,原值和修改值。方法里首先查看当前对象obj的锁是否可获得,获得之后调用java中Unsafe类的compareAndSwapInt方法,这个方法实现的方式是通过偏移量获得当前这个对象obj里相应成员的值,然后与传入的上个方法中获得的值比较,如果相等,说明当前没有其他对象对这个值进行了修改,当前可以执行修改;否则返回false,再次循环,直到值修改成功为止。
public int getAndAdd(T obj, int delta) {
int prev, next;
do {
prev = get(obj);
next = prev + delta;
} while (!compareAndSet(obj, prev, next));
return prev;
}
减少引用计数值的方法,最后都会调用如下这个函数。首先返回当前引用计数在内存中的值rawCnt,然后调用toLiveRealCnt返回当前引用计数的真实值realCnt,如果值为奇数,说明当前对象已经被释放,抛出非法引用计数异常,如果是偶数,则算法右移一位。再判断realCnt与decrement的值,如果相等,说明当前对象可能会被释放,直接调用refCntUpdater的compareAndSet方法将rawCnt的值设置为1,其底层会调用Unsafe类的compareAndSwapInt方法去修改引用的值,传入的rawCnt为当前获得的值,如果修改成功,说明没有其他线程对refCnt的值进行修改,还是当前的rawCnt,修改成功,调用deallocate释放当前对象;如果修改不成功,说明有其他线程对refCnt的值进行了修改,不是传入的rawCnt的值,所以调用retryRelease0再次处理。如果decrement 和realCnt的值不同,则直接调用releaseNonFinal0去处理
private boolean release0(int decrement) {
int rawCnt = nonVolatileRawCnt(), realCnt = toLiveRealCnt(rawCnt, decrement);
if (decrement == realCnt) {
if (refCntUpdater.compareAndSet(this, rawCnt, 1)) {
deallocate();
return true;
}
return retryRelease0(decrement);
}
return releaseNonFinal0(decrement, rawCnt, realCnt);
}
本函数使用一个自旋锁对realCnt的值进行修改,首先获得当前内存中refCnt的值rawCnt,然后调用toLiveRealCnt获得refCnt的真实值,然后判断decrement和realCnt两个值。如果相等,则将refCnt的值设置为1,设置成功之后释放对象,返回true,否则进行下次循环;如果decrement小于realCnt,则将refCnt的值减去decrement的两倍,设置成功之后返回false,否则进行下次循环;如果decrement大于realCnt,抛出引用计数异常错误。
private boolean retryRelease0(int decrement) {
for (;;) {
int rawCnt = refCntUpdater.get(this), realCnt = toLiveRealCnt(rawCnt, decrement);
if (decrement == realCnt) {
if (refCntUpdater.compareAndSet(this, rawCnt, 1)) {
deallocate();
return true;
}
} else if (decrement < realCnt) {
// all changes to the raw count are 2x the "real" change
if (refCntUpdater.compareAndSet(this, rawCnt, rawCnt - (decrement << 1))) {
return false;
}
} else {
throw new IllegalReferenceCountException(realCnt, -decrement);
}
Thread.yield(); // this benefits throughput under high contention
}
}
首先判断decrement和realCnt值的关系,如果小于,则去设置refCnt的值,设置成功之后直接返回false,否则调用retryRelease0方法
private boolean releaseNonFinal0(int decrement, int rawCnt, int realCnt) {
if (decrement < realCnt
// all changes to the raw count are 2x the "real" change
&& refCntUpdater.compareAndSet(this, rawCnt, rawCnt - (decrement << 1))) {
return false;
}
return retryRelease0(decrement);
}