前言
本文记录了学习Netty源码的过程,正片文章内容包含思路分析和大量源码。 @空歌白石
由于掘金文章长度限制只能将文章分为几部分。
本文主要包含:
- Netty简介。Netty源码剖析学习(一)
- Netty基本组件。Netty源码剖析学习(一)
- Netty服务端启动。Netty源码剖析学习(一)
- NioEventLoop。Netty源码剖析学习(一)
- Netty如何新建连接。Netty源码剖析学习(一)
- Pipeline。Netty源码剖析学习(二)
- Netty的内存分配ByteBuf。Netty源码剖析学习(二)
- Netty的解码逻辑。Netty源码剖析学习(二)
- Netty的编码逻辑。Netty源码剖析学习(二)
- Netty性能优化工具类。Netty源码剖析学习(三)
- Netty中的设计模式。Netty源码剖析学习(三)
注:本文源码为当前最新版本:netty 4.1
10. Netty性能优化工具类
- FastThreadLocal,重新实现了ThreadLocal。
- Recycler,实现了对象池的机制。
FastThreadLocal
package io.netty.util.concurrent;
import io.netty.util.internal.InternalThreadLocalMap;
import io.netty.util.internal.PlatformDependent;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;
public class FastThreadLocal<V> {
private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
public static void removeAll() {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
if (threadLocalMap == null) {
return;
}
try {
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
if (v != null && v != InternalThreadLocalMap.UNSET) {
@SuppressWarnings("unchecked")
Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
FastThreadLocal<?>[] variablesToRemoveArray =
variablesToRemove.toArray(new FastThreadLocal[0]);
for (FastThreadLocal<?> tlv: variablesToRemoveArray) {
tlv.remove(threadLocalMap);
}
}
} finally {
InternalThreadLocalMap.remove();
}
}
public static int size() {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
if (threadLocalMap == null) {
return 0;
} else {
return threadLocalMap.size();
}
}
public static void destroy() {
InternalThreadLocalMap.destroy();
}
@SuppressWarnings("unchecked")
private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
Set<FastThreadLocal<?>> variablesToRemove;
if (v == InternalThreadLocalMap.UNSET || v == null) {
variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());
threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
} else {
variablesToRemove = (Set<FastThreadLocal<?>>) v;
}
variablesToRemove.add(variable);
}
private static void removeFromVariablesToRemove(
InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
if (v == InternalThreadLocalMap.UNSET || v == null) {
return;
}
@SuppressWarnings("unchecked")
Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
variablesToRemove.remove(variable);
}
private final int index;
public FastThreadLocal() {
index = InternalThreadLocalMap.nextVariableIndex();
}
// 空歌白石:省略部分源码
}
private final class PoolThreadLocalCache extends FastThreadLocal<PoolThreadCache> {
private final boolean useCacheForAllThreads;
PoolThreadLocalCache(boolean useCacheForAllThreads) {
this.useCacheForAllThreads = useCacheForAllThreads;
}
@Override
protected synchronized PoolThreadCache initialValue() {
final PoolArena<byte[]> heapArena = leastUsedArena(heapArenas);
final PoolArena<ByteBuffer> directArena = leastUsedArena(directArenas);
final Thread current = Thread.currentThread();
final EventExecutor executor = ThreadExecutorMap.currentExecutor();
if (useCacheForAllThreads ||
// If the current thread is a FastThreadLocalThread we will always use the cache
current instanceof FastThreadLocalThread ||
// The Thread is used by an EventExecutor, let's use the cache as the chances are good that we
// will allocate a lot!
executor != null) {
final PoolThreadCache cache = new PoolThreadCache(
heapArena, directArena, smallCacheSize, normalCacheSize,
DEFAULT_MAX_CACHED_BUFFER_CAPACITY, DEFAULT_CACHE_TRIM_INTERVAL);
// 空歌白石:省略部分源码
}
@Override
protected void onRemoval(PoolThreadCache threadCache) {
threadCache.free(false);
}
// 空歌白石:省略部分源码
}
public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(InternalThreadLocalMap.class);
private static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap =
new ThreadLocal<InternalThreadLocalMap>();
private static final AtomicInteger nextIndex = new AtomicInteger();
private static final int DEFAULT_ARRAY_LIST_INITIAL_CAPACITY = 8;
private static final int ARRAY_LIST_CAPACITY_EXPAND_THRESHOLD = 1 << 30;
// Reference: https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/tip/src/share/classes/java/util/ArrayList.java#l229
private static final int ARRAY_LIST_CAPACITY_MAX_SIZE = Integer.MAX_VALUE - 8;
private static final int STRING_BUILDER_INITIAL_SIZE;
private static final int STRING_BUILDER_MAX_SIZE;
private static final int HANDLER_SHARABLE_CACHE_INITIAL_CAPACITY = 4;
private static final int INDEXED_VARIABLE_TABLE_INITIAL_SIZE = 32;
public static final Object UNSET = new Object();
/** Used by {@link FastThreadLocal} */
private Object[] indexedVariables;
// Core thread-locals
private int futureListenerStackDepth;
private int localChannelReaderStackDepth;
private Map<Class<?>, Boolean> handlerSharableCache;
private IntegerHolder counterHashCode;
private ThreadLocalRandom random;
private Map<Class<?>, TypeParameterMatcher> typeParameterMatcherGetCache;
private Map<Class<?>, Map<String, TypeParameterMatcher>> typeParameterMatcherFindCache;
// String-related thread-locals
private StringBuilder stringBuilder;
private Map<Charset, CharsetEncoder> charsetEncoderCache;
private Map<Charset, CharsetDecoder> charsetDecoderCache;
// ArrayList-related thread-locals
private ArrayList<Object> arrayList;
private BitSet cleanerFlags;
/** @deprecated These padding fields will be removed in the future. */
public long rp1, rp2, rp3, rp4, rp5, rp6, rp7, rp8;
static {
STRING_BUILDER_INITIAL_SIZE =
SystemPropertyUtil.getInt("io.netty.threadLocalMap.stringBuilder.initialSize", 1024);
logger.debug("-Dio.netty.threadLocalMap.stringBuilder.initialSize: {}", STRING_BUILDER_INITIAL_SIZE);
STRING_BUILDER_MAX_SIZE = SystemPropertyUtil.getInt("io.netty.threadLocalMap.stringBuilder.maxSize", 1024 * 4);
logger.debug("-Dio.netty.threadLocalMap.stringBuilder.maxSize: {}", STRING_BUILDER_MAX_SIZE);
}
// 空歌白石:省略部分源码
}
init
每一个FastThreadLocal
都有一个index,可以作为FastThreadLocal
的唯一标识。
private final int index;
public FastThreadLocal() {
index = InternalThreadLocalMap.nextVariableIndex();
}
private static final AtomicInteger nextIndex = new AtomicInteger();
// Reference: https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/tip/src/share/classes/java/util/ArrayList.java#l229
private static final int ARRAY_LIST_CAPACITY_MAX_SIZE = Integer.MAX_VALUE - 8;
public static int nextVariableIndex() {
int index = nextIndex.getAndIncrement();
if (index >= ARRAY_LIST_CAPACITY_MAX_SIZE || index < 0) {
nextIndex.set(ARRAY_LIST_CAPACITY_MAX_SIZE);
throw new IllegalStateException("too many thread-local indexed variables");
}
return index;
}
get
- 获取ThreadLocalMap
- 直接通过索引取出对象
- 初始化
@SuppressWarnings("unchecked")
public final V get() {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
Object v = threadLocalMap.indexedVariable(index);
if (v != InternalThreadLocalMap.UNSET) {
return (V) v;
}
return initialize(threadLocalMap);
}
public static InternalThreadLocalMap get() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {
return fastGet((FastThreadLocalThread) thread);
} else {
return slowGet();
}
}
FastThreadLocalThread
public class FastThreadLocalThread extends Thread {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(FastThreadLocalThread.class);
// This will be set to true if we have a chance to wrap the Runnable.
private final boolean cleanupFastThreadLocals;
private InternalThreadLocalMap threadLocalMap;
// 空歌白石:省略部分源码
public FastThreadLocalThread(ThreadGroup group, Runnable target, String name, long stackSize) {
super(group, FastThreadLocalRunnable.wrap(target), name, stackSize);
cleanupFastThreadLocals = true;
}
// 空歌白石:省略部分源码
}
private V initialize(InternalThreadLocalMap threadLocalMap) {
V v = null;
try {
v = initialValue();
} catch (Exception e) {
PlatformDependent.throwException(e);
}
threadLocalMap.setIndexedVariable(index, v);
addToVariablesToRemove(threadLocalMap, this);
return v;
}
public boolean setIndexedVariable(int index, Object value) {
Object[] lookup = indexedVariables;
if (index < lookup.length) {
Object oldValue = lookup[index];
lookup[index] = value;
return oldValue == UNSET;
} else {
expandIndexedVariableTableAndSet(index, value);
return true;
}
}
set
- 获取ThreadLocalMap
- 直接通过索引set对象
- 如果是UNSET对象则remove对象
public final void set(V value) {
if (value != InternalThreadLocalMap.UNSET) {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
setKnownNotUnset(threadLocalMap, value);
} else {
remove();
}
}
public final void set(InternalThreadLocalMap threadLocalMap, V value) {
if (value != InternalThreadLocalMap.UNSET) {
setKnownNotUnset(threadLocalMap, value);
} else {
remove(threadLocalMap);
}
}
@SuppressWarnings("unchecked")
public final void remove(InternalThreadLocalMap threadLocalMap) {
if (threadLocalMap == null) {
return;
}
Object v = threadLocalMap.removeIndexedVariable(index);
removeFromVariablesToRemove(threadLocalMap, this);
if (v != InternalThreadLocalMap.UNSET) {
try {
onRemoval((V) v);
} catch (Exception e) {
PlatformDependent.throwException(e);
}
}
}
Recycler
Recycler
是一个轻量级的对象池实现。通过重用池,可以有效减少YoungGC的次数。
public abstract class Recycler<T> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Recycler.class);
private static final Handle<?> NOOP_HANDLE = new Handle<Object>() {
@Override
public void recycle(Object object) {
// NOOP
}
@Override
public String toString() {
return "NOOP_HANDLE";
}
};
private static final int DEFAULT_INITIAL_MAX_CAPACITY_PER_THREAD = 4 * 1024; // Use 4k instances as default.
private static final int DEFAULT_MAX_CAPACITY_PER_THREAD;
private static final int RATIO;
private static final int DEFAULT_QUEUE_CHUNK_SIZE_PER_THREAD;
private static final boolean BLOCKING_POOL;
static {
// In the future, we might have different maxCapacity for different object types.
// e.g. io.netty.recycler.maxCapacity.writeTask
// io.netty.recycler.maxCapacity.outboundBuffer
int maxCapacityPerThread = SystemPropertyUtil.getInt("io.netty.recycler.maxCapacityPerThread",
SystemPropertyUtil.getInt("io.netty.recycler.maxCapacity", DEFAULT_INITIAL_MAX_CAPACITY_PER_THREAD));
if (maxCapacityPerThread < 0) {
maxCapacityPerThread = DEFAULT_INITIAL_MAX_CAPACITY_PER_THREAD;
}
DEFAULT_MAX_CAPACITY_PER_THREAD = maxCapacityPerThread;
DEFAULT_QUEUE_CHUNK_SIZE_PER_THREAD = SystemPropertyUtil.getInt("io.netty.recycler.chunkSize", 32);
// By default we allow one push to a Recycler for each 8th try on handles that were never recycled before.
// This should help to slowly increase the capacity of the recycler while not be too sensitive to allocation
// bursts.
RATIO = max(0, SystemPropertyUtil.getInt("io.netty.recycler.ratio", 8));
BLOCKING_POOL = SystemPropertyUtil.getBoolean("io.netty.recycler.blocking", false);
// 空歌白石:省略部分源码
}
private final int maxCapacityPerThread;
private final int interval;
private final int chunkSize;
private final FastThreadLocal<LocalPool<T>> threadLocal = new FastThreadLocal<LocalPool<T>>() {
@Override
protected LocalPool<T> initialValue() {
return new LocalPool<T>(maxCapacityPerThread, interval, chunkSize);
}
@Override
protected void onRemoval(LocalPool<T> value) throws Exception {
super.onRemoval(value);
MessagePassingQueue<DefaultHandle<T>> handles = value.pooledHandles;
value.pooledHandles = null;
handles.clear();
}
};
// 空歌白石:省略部分源码
protected Recycler(int maxCapacityPerThread, int ratio, int chunkSize) {
interval = max(0, ratio);
if (maxCapacityPerThread <= 0) {
this.maxCapacityPerThread = 0;
this.chunkSize = 0;
} else {
this.maxCapacityPerThread = max(4, maxCapacityPerThread);
this.chunkSize = max(2, min(chunkSize, this.maxCapacityPerThread >> 1));
}
}
从Recycler获取对象
- 获取当前线程的LocalPool
- 从LocalPool里弹出对象
- 创建对象并绑定到LocalPool中
public final T get() {
if (maxCapacityPerThread == 0) {
return newObject((Handle<T>) NOOP_HANDLE);
}
LocalPool<T> localPool = threadLocal.get();
DefaultHandle<T> handle = localPool.claim();
T obj;
if (handle == null) {
handle = localPool.newHandle();
if (handle != null) {
obj = newObject(handle);
handle.set(obj);
} else {
obj = newObject((Handle<T>) NOOP_HANDLE);
}
} else {
obj = handle.get();
}
return obj;
}
回收对象
- 同线程回收对象
- 不同线程回收对象
@Deprecated
public final boolean recycle(T o, Handle<T> handle) {
if (handle == NOOP_HANDLE) {
return false;
}
handle.recycle(o);
return true;
}
@Override
public void recycle(Object object) {
if (object != value) {
throw new IllegalArgumentException("object does not belong to handle");
}
localPool.release(this);
}
void toAvailable() {
int prev = STATE_UPDATER.getAndSet(this, STATE_AVAILABLE);
if (prev == STATE_AVAILABLE) {
throw new IllegalStateException("Object has been recycled already.");
}
}
DefaultHandle
private static final class DefaultHandle<T> implements Handle<T> {
private static final int STATE_CLAIMED = 0;
private static final int STATE_AVAILABLE = 1;
private static final AtomicIntegerFieldUpdater<DefaultHandle<?>> STATE_UPDATER;
static {
AtomicIntegerFieldUpdater<?> updater = AtomicIntegerFieldUpdater.newUpdater(DefaultHandle.class, "state");
//noinspection unchecked
STATE_UPDATER = (AtomicIntegerFieldUpdater<DefaultHandle<?>>) updater;
}
@SuppressWarnings({"FieldMayBeFinal", "unused"}) // Updated by STATE_UPDATER.
private volatile int state; // State is initialised to STATE_CLAIMED (aka. 0) so they can be released.
private final LocalPool<T> localPool;
private T value;
DefaultHandle(LocalPool<T> localPool) {
this.localPool = localPool;
}
// 空歌白石:省略部分源码
}
LocalPool
private static final class LocalPool<T> {
private final int ratioInterval;
private volatile MessagePassingQueue<DefaultHandle<T>> pooledHandles;
private int ratioCounter;
@SuppressWarnings("unchecked")
LocalPool(int maxCapacity, int ratioInterval, int chunkSize) {
this.ratioInterval = ratioInterval;
if (BLOCKING_POOL) {
pooledHandles = new BlockingMessageQueue<DefaultHandle<T>>(maxCapacity);
} else {
pooledHandles = (MessagePassingQueue<DefaultHandle<T>>) newMpscQueue(chunkSize, maxCapacity);
}
ratioCounter = ratioInterval; // Start at interval so the first one will be recycled.
}
// 空歌白石:省略部分源码
}
BlockingMessageQueue
private static final class BlockingMessageQueue<T> implements MessagePassingQueue<T> {
private final Queue<T> deque;
private final int maxCapacity;
BlockingMessageQueue(int maxCapacity) {
this.maxCapacity = maxCapacity;
deque = new ArrayDeque<T>();
}
// 空歌白石:省略部分源码
}
ObjectPool
ObjectPool
依赖于Recycler
实现对象池。
public abstract class ObjectPool<T> {
ObjectPool() { }
public abstract T get();
public interface Handle<T> {
/**
* Recycle the {@link Object} if possible and so make it ready to be reused.
*/
void recycle(T self);
}
public interface ObjectCreator<T> {
T newObject(Handle<T> handle);
}
// 空歌白石:省略部分源码
}
总结
FastThreadLocal
之所以比ThreadLocal
快,主要因为FastThreadLocal
使用下标index查找Local,而JDK的ThreadLocal使用的hash等,显然FastThreadLocal
的·
o(1)`复杂度的操作更快。- 解决线程变量隔离
- 轻量级对象池
Recycler
可以快速取对象,回收也更快,减少了YoungGC的次数。如果对象的属性过少,使用Recycler也可能并不划算。- 解决对象重用,
Recycler
依赖于FastThreadLocal
。
- 解决对象重用,
以上两种方法的思想或方法可以直接在具体的项目中使用。
11. Netty中的设计模式实现
单例模式
- 一个类全局只有一个对象
- 延迟创建
- 避免线程安全问题
ReadTimeoutException
package io.netty.handler.timeout;
import io.netty.util.internal.PlatformDependent;
public final class ReadTimeoutException extends TimeoutException {
private static final long serialVersionUID = 169287984113283421L;
public static final ReadTimeoutException INSTANCE = PlatformDependent.javaVersion() >= 7 ?
new ReadTimeoutException(true) : new ReadTimeoutException();
public ReadTimeoutException() { }
public ReadTimeoutException(String message) {
super(message, false);
}
private ReadTimeoutException(boolean shared) {
super(null, shared);
}
}
MqttEncoder
@ChannelHandler.Sharable
public final class MqttEncoder extends MessageToMessageEncoder<MqttMessage> {
public static final MqttEncoder INSTANCE = new MqttEncoder();
private MqttEncoder() { }
}
策略模式
- 封装一系列可相互替代的算法家族
- 动态选择某一个策略,需要路由到具体的策略实现
DefaultEventExecutorChooserFactory
@UnstableApi
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {
public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();
private DefaultEventExecutorChooserFactory() { }
@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
// 空歌白石:策略模式
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
private static boolean isPowerOfTwo(int val) {
return (val & -val) == val;
}
private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
}
private static final class GenericEventExecutorChooser implements EventExecutorChooser {
// Use a 'long' counter to avoid non-round-robin behaviour at the 32-bit overflow boundary.
// The 64-bit long solves this by placing the overflow so far into the future, that no system
// will encounter this in practice.
private final AtomicLong idx = new AtomicLong();
private final EventExecutor[] executors;
GenericEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[(int) Math.abs(idx.getAndIncrement() % executors.length)];
}
}
}
@UnstableApi
public interface EventExecutorChooserFactory {
EventExecutorChooser newChooser(EventExecutor[] executors);
@UnstableApi
interface EventExecutorChooser {
EventExecutor next();
}
}
装饰者模式
- 装饰者和被装饰者继承同一个接口
- 装饰者给被装饰者动态修改行为
WrappedByteBuf
WrappedByteBuf
装饰了ByteBuf
。
class WrappedByteBuf extends ByteBuf {
protected final ByteBuf buf;
protected WrappedByteBuf(ByteBuf buf) {
this.buf = ObjectUtil.checkNotNull(buf, "buf");
}
@Override
public final boolean hasMemoryAddress() {
return buf.hasMemoryAddress();
}
@Override
public boolean isContiguous() {
return buf.isContiguous();
}
}
UnreleasableByteBuf
UnreleasableByteBuf
装饰了WrappedByteBuf
。release
覆盖了WrappedByteBuf
的实现。
final class UnreleasableByteBuf extends WrappedByteBuf {
private SwappedByteBuf swappedBuf;
UnreleasableByteBuf(ByteBuf buf) {
super(buf instanceof UnreleasableByteBuf ? buf.unwrap() : buf);
}
@Override
public ByteBuf order(ByteOrder endianness) {
if (ObjectUtil.checkNotNull(endianness, "endianness") == order()) {
return this;
}
SwappedByteBuf swappedBuf = this.swappedBuf;
if (swappedBuf == null) {
this.swappedBuf = swappedBuf = new SwappedByteBuf(this);
}
return swappedBuf;
}
@Override
public ByteBuf asReadOnly() {
return buf.isReadOnly() ? this : new UnreleasableByteBuf(buf.asReadOnly());
}
@Override
public boolean release() {
return false;
}
}
SimpleLeakAwareByteBuf
SimpleLeakAwareByteBuf
装饰了WrappedByteBuf
。release
覆盖了WrappedByteBuf
的实现。
class SimpleLeakAwareByteBuf extends WrappedByteBuf {
private final ByteBuf trackedByteBuf;
final ResourceLeakTracker<ByteBuf> leak;
SimpleLeakAwareByteBuf(ByteBuf wrapped, ByteBuf trackedByteBuf, ResourceLeakTracker<ByteBuf> leak) {
super(wrapped);
this.trackedByteBuf = ObjectUtil.checkNotNull(trackedByteBuf, "trackedByteBuf");
this.leak = ObjectUtil.checkNotNull(leak, "leak");
}
SimpleLeakAwareByteBuf(ByteBuf wrapped, ResourceLeakTracker<ByteBuf> leak) {
this(wrapped, wrapped, leak);
}
// 空歌白石:省略部分源码
package io.netty.util;
public interface ResourceLeakTracker<T> {
void record();
void record(Object hint);
boolean close(T trackedObject);
}
观察者模式
- 观察者和被观察者
- 观察者订阅消息,被观察者发布消息
- 订阅则能收到消息,取消订阅则收不到消息
ChannelFuture
addListeners
方法是在添加观察者。
public interface ChannelFuture extends Future<Void> {
Channel channel();
// 空歌白石:省略部分源码
}
AbstractChannelHandlerContext
@Override
public ChannelFuture writeAndFlush(Object msg) {
return writeAndFlush(msg, newPromise());
}
创建观察者。
@Override
public ChannelPromise newPromise() {
return new DefaultChannelPromise(channel(), executor());
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
write(msg, true, promise);
return promise;
}
private void write(Object msg, boolean flush, ChannelPromise promise) {
ObjectUtil.checkNotNull(msg, "msg");
try {
if (isNotValidPromise(promise, true)) {
ReferenceCountUtil.release(msg);
// cancelled
return;
}
} catch (RuntimeException e) {
ReferenceCountUtil.release(msg);
throw e;
}
final AbstractChannelHandlerContext next = findContextOutbound(flush ?
(MASK_WRITE | MASK_FLUSH) : MASK_WRITE);
final Object m = pipeline.touch(msg, next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
if (flush) {
next.invokeWriteAndFlush(m, promise);
} else {
next.invokeWrite(m, promise);
}
} else {
final WriteTask task = WriteTask.newInstance(next, m, promise, flush);
if (!safeExecute(executor, task, promise, m, !flush)) {
task.cancel();
}
}
}
DefaultChannelPromise
public class DefaultChannelPromise extends DefaultPromise<Void> implements ChannelPromise, FlushCheckpoint {
private final Channel channel;
private long checkpoint;
public DefaultChannelPromise(Channel channel) {
this.channel = checkNotNull(channel, "channel");
}
public DefaultChannelPromise(Channel channel, EventExecutor executor) {
super(executor);
this.channel = checkNotNull(channel, "channel");
}
// 空歌白石:省略部分源码
}
DefaultPromise
/**
* One or more listeners. Can be a {@link GenericFutureListener} or a {@link DefaultFutureListeners}.
* If {@code null}, it means either 1) no listeners were added yet or 2) all listeners were notified.
*
* Threading - synchronized(this). We must support adding listeners when there is no EventExecutor.
*/
private Object listeners;
/**
* Threading - synchronized(this). We are required to hold the monitor to use Java's underlying wait()/notifyAll().
*/
private short waiters;
/**
* Threading - synchronized(this). We must prevent concurrent notification and FIFO listener notification if the
* executor changes.
*/
private boolean notifyingListeners;
@Override
public Promise<V> addListeners(GenericFutureListener<? extends Future<? super V>>... listeners) {
checkNotNull(listeners, "listeners");
synchronized (this) {
for (GenericFutureListener<? extends Future<? super V>> listener : listeners) {
if (listener == null) {
break;
}
addListener0(listener);
}
}
if (isDone()) {
notifyListeners();
}
return this;
}
private void addListener0(GenericFutureListener<? extends Future<? super V>> listener) {
if (listeners == null) {
listeners = listener;
} else if (listeners instanceof DefaultFutureListeners) {
((DefaultFutureListeners) listeners).add(listener);
} else {
listeners = new DefaultFutureListeners((GenericFutureListener<?>) listeners, listener);
}
}
private void notifyListeners() {
EventExecutor executor = executor();
if (executor.inEventLoop()) {
final InternalThreadLocalMap threadLocals = InternalThreadLocalMap.get();
final int stackDepth = threadLocals.futureListenerStackDepth();
if (stackDepth < MAX_LISTENER_STACK_DEPTH) {
threadLocals.setFutureListenerStackDepth(stackDepth + 1);
try {
notifyListenersNow();
} finally {
threadLocals.setFutureListenerStackDepth(stackDepth);
}
return;
}
}
safeExecute(executor, new Runnable() {
// 空歌白石:省略部分源码
notifyListenersNow();
// 空歌白石:省略部分源码
});
}
private void notifyListenersNow() {
// 空歌白石:省略部分源码
for (;;) {
if (listeners instanceof DefaultFutureListeners) {
notifyListeners0((DefaultFutureListeners) listeners);
} else {
notifyListener0(this, (GenericFutureListener<?>) listeners);
}
// 空歌白石:省略部分源码
}
}
迭代器模式
netty使用迭代器模式,可以做到内存的ZeroCopy。
- 迭代器接口
- 对容器里面各个对象进行访问
ByteBuf
public abstract int forEachByte(ByteProcessor processor);
public abstract int forEachByte(int index, int length, ByteProcessor processor);
public abstract int forEachByteDesc(ByteProcessor processor);
public abstract int forEachByteDesc(int index, int length, ByteProcessor processor);
AbstractByteBuf
@Override
public int forEachByte(ByteProcessor processor) {
ensureAccessible();
try {
return forEachByteAsc0(readerIndex, writerIndex, processor);
} catch (Exception e) {
PlatformDependent.throwException(e);
return -1;
}
}
int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception {
for (; start < end; ++start) {
if (!processor.process(_getByte(start))) {
return start;
}
}
return -1;
}
CompositeByteBuf
@Override
protected int forEachByteAsc0(int start, int end, ByteProcessor processor) throws Exception {
if (end <= start) {
return -1;
}
for (int i = toComponentIndex0(start), length = end - start; length > 0; i++) {
Component c = components[i];
if (c.offset == c.endOffset) {
continue; // empty
}
ByteBuf s = c.buf;
int localStart = c.idx(start);
int localLength = Math.min(length, c.endOffset - start);
// avoid additional checks in AbstractByteBuf case
int result = s instanceof AbstractByteBuf
? ((AbstractByteBuf) s).forEachByteAsc0(localStart, localStart + localLength, processor)
: s.forEachByte(localStart, localLength, processor);
if (result != -1) {
return result - c.adjustment;
}
start += localLength;
length -= localLength;
}
return -1;
}
public CompositeByteBuf addComponent(boolean increaseWriterIndex, ByteBuf buffer) {
return addComponent(increaseWriterIndex, componentCount, buffer);
}
public CompositeByteBuf addComponent(boolean increaseWriterIndex, int cIndex, ByteBuf buffer) {
checkNotNull(buffer, "buffer");
addComponent0(increaseWriterIndex, cIndex, buffer);
consolidateIfNeeded();
return this;
}
责任链模式
使得多个对象都有机会处理同一请求,避免请求的发送者和接受者的耦合关系。每个处理对象选择是否处理责任链的请求。
- 责任处理器接口
- 创建责任链,添加删除责任处理器接口
- 上下文的集合
- 责任终止机制
Head <-> TaskA <-> TaskC <-> TaskB <-> Tail
ChannelHandler(责任处理器接口)
public interface ChannelHandler {
void handlerAdded(ChannelHandlerContext ctx) throws Exception;
void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
@Deprecated
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Sharable {
// no value
}
}
ChannelInboundHandler
public interface ChannelInboundHandler extends ChannelHandler {
void channelRegistered(ChannelHandlerContext ctx) throws Exception;
void channelUnregistered(ChannelHandlerContext ctx) throws Exception;
void channelActive(ChannelHandlerContext ctx) throws Exception;
void channelInactive(ChannelHandlerContext ctx) throws Exception;
void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;
void channelReadComplete(ChannelHandlerContext ctx) throws Exception;
void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;
void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception;
@Override
@SuppressWarnings("deprecation")
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}
ChannelOutboundHandler
public interface ChannelOutboundHandler extends ChannelHandler {
void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception;
void connect(
ChannelHandlerContext ctx, SocketAddress remoteAddress,
SocketAddress localAddress, ChannelPromise promise) throws Exception;
void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception;
void read(ChannelHandlerContext ctx) throws Exception;
void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception;
void flush(ChannelHandlerContext ctx) throws Exception;
}
ChannelPipeline(责任链)
public interface ChannelPipeline
extends ChannelInboundInvoker, ChannelOutboundInvoker, Iterable<Entry<String, ChannelHandler>> {
ChannelPipeline addFirst(String name, ChannelHandler handler);
ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler);
// 空歌白石:省略部分源码
}
ChannelHandlerContext(上下文)
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {
/**
* Return the {@link Channel} which is bound to the {@link ChannelHandlerContext}.
*/
Channel channel();
/**
* Returns the {@link EventExecutor} which is used to execute an arbitrary task.
*/
EventExecutor executor();
// 空歌白石:省略部分源码
}
责任终止机制
通过链表来向下传播,或向上终止。
ChannelHandlerContext
@Override
ChannelHandlerContext fireChannelRegistered();
@Override
ChannelHandlerContext fireChannelUnregistered();
@Override
ChannelHandlerContext fireChannelActive();
@Override
ChannelHandlerContext fireChannelInactive();
@Override
ChannelHandlerContext fireExceptionCaught(Throwable cause);
@Override
ChannelHandlerContext fireUserEventTriggered(Object evt);
@Override
ChannelHandlerContext fireChannelRead(Object msg);
@Override
ChannelHandlerContext fireChannelReadComplete();
@Override
ChannelHandlerContext fireChannelWritabilityChanged();
ChannelInboundHandlerAdapter
@Skip
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
}
@Skip
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.fireChannelRead(msg);
}
结束语
由于篇幅原因,将文章分为了三部分,本文是Netty源码剖析学习的最后一篇。
后续将针对Netty中在实际开发中由借鉴意义的设计原理和模块进行专题的分析。希望能够帮助到大家。