From d0a3c2d95e446a25fd2b1a2e9e22e0b1c4bb5504 Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Wed, 13 Feb 2013 16:38:20 -0800 Subject: [PATCH] Reduce the memory footprint of DefaultChannelPromise --- .../netty/channel/DefaultChannelPromise.java | 102 ++++++++++-------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/transport/src/main/java/io/netty/channel/DefaultChannelPromise.java b/transport/src/main/java/io/netty/channel/DefaultChannelPromise.java index 1b874013bd..fbdece047d 100644 --- a/transport/src/main/java/io/netty/channel/DefaultChannelPromise.java +++ b/transport/src/main/java/io/netty/channel/DefaultChannelPromise.java @@ -16,11 +16,11 @@ package io.netty.channel; import io.netty.channel.ChannelFlushPromiseNotifier.FlushCheckpoint; +import io.netty.util.Signal; import io.netty.util.internal.InternalLogger; import io.netty.util.internal.InternalLoggerFactory; import java.util.ArrayList; -import java.util.List; import java.util.concurrent.TimeUnit; import static java.util.concurrent.TimeUnit.*; @@ -42,11 +42,11 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro } }; + private static final Signal SUCCESS = new Signal(DefaultChannelPromise.class.getName() + ".SUCCESS"); + private final Channel channel; - private ChannelFutureListener firstListener; - private List otherListeners; - private boolean done; + private Object listeners; // Can be ChannelFutureListener or DefaultChannelPromiseListeners private Throwable cause; private int waiters; @@ -72,17 +72,21 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro @Override public synchronized boolean isDone() { - return done; + return cause != null; } @Override public synchronized boolean isSuccess() { - return done && cause == null; + return cause == SUCCESS; } @Override - public synchronized Throwable cause() { - return cause; + public Throwable cause() { + Throwable cause; + synchronized (this) { + cause = this.cause; + } + return cause == SUCCESS? null : cause; } @Override @@ -93,16 +97,17 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro boolean notifyNow = false; synchronized (this) { - if (done) { + if (cause != null) { notifyNow = true; } else { - if (firstListener == null) { - firstListener = listener; + if (listeners == null) { + listeners = listener; } else { - if (otherListeners == null) { - otherListeners = new ArrayList(1); + if (listeners instanceof DefaultChannelPromiseListeners) { + ((DefaultChannelPromiseListeners) listeners).add(listener); + } else { + listeners = new DefaultChannelPromiseListeners((ChannelFutureListener) listeners, listener); } - otherListeners.add(listener); } } } @@ -136,15 +141,11 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro } synchronized (this) { - if (!done) { - if (listener == firstListener) { - if (otherListeners != null && !otherListeners.isEmpty()) { - firstListener = otherListeners.remove(0); - } else { - firstListener = null; - } - } else if (otherListeners != null) { - otherListeners.remove(listener); + if (cause == null) { + if (listeners instanceof DefaultChannelPromiseListeners) { + ((DefaultChannelPromiseListeners) listeners).remove(listener); + } else if (listeners == listener) { + listeners = null; } } } @@ -205,7 +206,7 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro } synchronized (this) { - while (!done) { + while (cause == null) { checkDeadLock(); waiters++; try { @@ -233,7 +234,7 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro public ChannelPromise awaitUninterruptibly() { boolean interrupted = false; synchronized (this) { - while (!done) { + while (cause == null) { checkDeadLock(); waiters++; try { @@ -282,8 +283,8 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro try { synchronized (this) { - if (done || waitTime <= 0) { - return done; + if (cause != null || waitTime <= 0) { + return cause != null; } checkDeadLock(); @@ -300,12 +301,12 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro } } - if (done) { + if (cause != null) { return true; } else { waitTime = timeoutNanos - (System.nanoTime() - startTime); if (waitTime <= 0) { - return done; + return cause != null; } } } @@ -346,11 +347,11 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro private synchronized boolean success0() { // Allow only once. - if (done) { + if (cause != null) { return false; } - done = true; + cause = SUCCESS; if (waiters > 0) { notifyAll(); } @@ -377,12 +378,11 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro private synchronized boolean failure0(Throwable cause) { // Allow only once. - if (done) { + if (cause != null) { return false; } this.cause = cause; - done = true; if (waiters > 0) { notifyAll(); } @@ -396,33 +396,31 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro // 2) This method is called only when 'done' is true. Once 'done' // becomes true, the listener list is never modified - see add/removeListener() - if (firstListener == null) { + if (listeners == null) { return; } if (channel().eventLoop().inEventLoop()) { - notifyListener0(this, firstListener); - firstListener = null; - - if (otherListeners != null) { - for (ChannelFutureListener l: otherListeners) { + if (listeners instanceof DefaultChannelPromiseListeners) { + for (ChannelFutureListener l : (DefaultChannelPromiseListeners) listeners) { notifyListener0(this, l); } - otherListeners = null; + } else { + notifyListener0(this, (ChannelFutureListener) listeners); } + listeners = null; } else { - final ChannelFutureListener firstListener = this.firstListener; - final List otherListeners = this.otherListeners; - this.firstListener = null; - this.otherListeners = null; + final Object listeners = this.listeners; + this.listeners = null; channel().eventLoop().execute(new Runnable() { @Override public void run() { - notifyListener0(DefaultChannelPromise.this, firstListener); - if (otherListeners != null) { - for (ChannelFutureListener l: otherListeners) { + if (listeners instanceof DefaultChannelPromiseListeners) { + for (ChannelFutureListener l : (DefaultChannelPromiseListeners) listeners) { notifyListener0(DefaultChannelPromise.this, l); } + } else { + notifyListener0(DefaultChannelPromise.this, (ChannelFutureListener) listeners); } } }); @@ -478,4 +476,14 @@ public class DefaultChannelPromise extends FlushCheckpoint implements ChannelPro ChannelPromise future() { return this; } + + private static final class DefaultChannelPromiseListeners extends ArrayList { + private static final long serialVersionUID = 7414281537694651180L; + + DefaultChannelPromiseListeners(ChannelFutureListener firstListener, ChannelFutureListener secondListener) { + super(2); + add(firstListener); + add(secondListener); + } + } }