Make sure ChannelFutureAggregator is thread-safe and only hold the lock

as short as possible. This also change it to lazy init the HashSet that
holds the ChannelFuture's. See #90
This commit is contained in:
norman 2011-11-30 13:45:51 +01:00
parent da3a52778b
commit d2278a7d53

View File

@ -33,20 +33,24 @@ public class ChannelFutureAggregator implements ChannelFutureListener {
private final ChannelFuture aggregateFuture; private final ChannelFuture aggregateFuture;
private final Set<ChannelFuture> pendingFutures; private Set<ChannelFuture> pendingFutures;
public ChannelFutureAggregator(ChannelFuture aggregateFuture) { public ChannelFutureAggregator(ChannelFuture aggregateFuture) {
this.aggregateFuture = aggregateFuture; this.aggregateFuture = aggregateFuture;
pendingFutures = new HashSet<ChannelFuture>();
} }
public void addFuture(ChannelFuture future) { public void addFuture(ChannelFuture future) {
synchronized(this) {
if (pendingFutures == null) {
pendingFutures = new HashSet<ChannelFuture>();
}
pendingFutures.add(future); pendingFutures.add(future);
}
future.addListener(this); future.addListener(this);
} }
@Override @Override
public synchronized void operationComplete(ChannelFuture future) public void operationComplete(ChannelFuture future)
throws Exception { throws Exception {
if (future.isCancelled()) { if (future.isCancelled()) {
// TODO: what should the correct behaviour be when a fragment is cancelled? // TODO: what should the correct behaviour be when a fragment is cancelled?
@ -54,17 +58,24 @@ public class ChannelFutureAggregator implements ChannelFutureListener {
return; return;
} }
synchronized (this) {
if (pendingFutures == null) {
aggregateFuture.setSuccess();
} else {
pendingFutures.remove(future); pendingFutures.remove(future);
if (!future.isSuccess()) { if (!future.isSuccess()) {
aggregateFuture.setFailure(future.getCause()); aggregateFuture.setFailure(future.getCause());
for (ChannelFuture pendingFuture: pendingFutures) { for (ChannelFuture pendingFuture: pendingFutures) {
pendingFuture.cancel(); pendingFuture.cancel();
} }
return; } else {
}
if (pendingFutures.isEmpty()) { if (pendingFutures.isEmpty()) {
aggregateFuture.setSuccess(); aggregateFuture.setSuccess();
} }
} }
} }
}
}
}