[#1120] Make sure releaseExternal() can not cause a deadlock if the ExecutorService is shared

This commit is contained in:
Norman Maurer 2013-03-27 09:30:25 +01:00
parent 7013315fd4
commit bce398819a
7 changed files with 53 additions and 24 deletions

View File

@ -88,7 +88,7 @@ public abstract class AbstractNioBossPool<E extends Boss>
public void releaseExternalResources() {
shutdown();
ExecutorUtil.terminate(bossExecutor);
ExecutorUtil.shutdownNow(bossExecutor);
}
public void shutdown() {

View File

@ -112,7 +112,7 @@ public abstract class AbstractNioWorkerPool<E extends AbstractNioWorker>
public void releaseExternalResources() {
shutdown();
ExecutorUtil.terminate(workerExecutor);
ExecutorUtil.shutdownNow(workerExecutor);
}
public void shutdown() {

View File

@ -122,12 +122,12 @@ public class OioClientSocketChannelFactory implements ClientSocketChannelFactory
public void shutdown() {
if (shutdownExecutor) {
ExecutorUtil.terminate(workerExecutor);
ExecutorUtil.shutdownNow(workerExecutor);
}
}
public void releaseExternalResources() {
shutdown();
ExecutorUtil.terminate(workerExecutor);
ExecutorUtil.shutdownNow(workerExecutor);
}
}

View File

@ -121,12 +121,12 @@ public class OioDatagramChannelFactory implements DatagramChannelFactory {
public void shutdown() {
if (shutdownExecutor) {
ExecutorUtil.terminate(workerExecutor);
ExecutorUtil.shutdownNow(workerExecutor);
}
}
public void releaseExternalResources() {
shutdown();
ExecutorUtil.terminate(workerExecutor);
ExecutorUtil.shutdownNow(workerExecutor);
}
}

View File

@ -145,12 +145,12 @@ public class OioServerSocketChannelFactory implements ServerSocketChannelFactory
public void shutdown() {
if (shutdownExecutor) {
ExecutorUtil.terminate(workerExecutor);
ExecutorUtil.shutdownNow(workerExecutor);
}
}
public void releaseExternalResources() {
shutdown();
ExecutorUtil.terminate(workerExecutor);
ExecutorUtil.shutdownNow(workerExecutor);
}
}

View File

@ -27,6 +27,30 @@ import java.util.concurrent.TimeUnit;
*/
public final class ExecutorUtil {
/**
* Try to call {@link ExecutorService#shutdownNow()}
*/
public static void shutdownNow(Executor executor) {
if (executor instanceof ExecutorService) {
ExecutorService es = (ExecutorService) executor;
try {
es.shutdownNow();
} catch (SecurityException ex) {
// Running in a restricted environment - fall back.
try {
es.shutdown();
} catch (SecurityException ex2) {
// Running in a more restricted environment.
// Can't shut down this executor - skip to the next.
} catch (NullPointerException ex2) {
// Some JDK throws NPE here, but shouldn't.
}
} catch (NullPointerException ex) {
// Some JDK throws NPE here, but shouldn't.
}
}
}
/**
* Returns {@code true} if and only if the specified {@code executor}
* is an {@link ExecutorService} and is shut down. Please note that this
@ -88,22 +112,7 @@ public final class ExecutorUtil {
ExecutorService es = (ExecutorService) e;
for (;;) {
try {
es.shutdownNow();
} catch (SecurityException ex) {
// Running in a restricted environment - fall back.
try {
es.shutdown();
} catch (SecurityException ex2) {
// Running in a more restricted environment.
// Can't shut down this executor - skip to the next.
break;
} catch (NullPointerException ex2) {
// Some JDK throws NPE here, but shouldn't.
}
} catch (NullPointerException ex) {
// Some JDK throws NPE here, but shouldn't.
}
shutdownNow(es);
try {
if (es.awaitTermination(100, TimeUnit.MILLISECONDS)) {

View File

@ -24,11 +24,15 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.util.DummyHandler;
import org.junit.Test;
@ -271,4 +275,20 @@ public class BootstrapTest {
protected Bootstrap newBootstrap() {
return new Bootstrap();
}
@Test
public void testReleaseSharedNotDeadlock() {
// create bootstraps
final ExecutorService pool = Executors.newFixedThreadPool(2);
final ClientBootstrap client = new ClientBootstrap(
new NioClientSocketChannelFactory(pool,
Executors.newCachedThreadPool()));
final ServerBootstrap server = new ServerBootstrap(
new NioServerSocketChannelFactory(pool,
Executors.newCachedThreadPool()));
// release resources
client.releaseExternalResources();
server.releaseExternalResources();
}
}