Issue 346: fixed executor doesn't close problem

This commit is contained in:
Adrian Cole 2010-09-10 17:47:24 -07:00
parent 53adab1ab4
commit 6a8382773e
3 changed files with 66 additions and 18 deletions

View File

@ -72,8 +72,10 @@ public class ExecutorServiceModule extends AbstractModule {
}
}
private final ExecutorService userExecutorFromConstructor;
private final ExecutorService ioExecutorFromConstructor;
@VisibleForTesting
final ExecutorService userExecutorFromConstructor;
@VisibleForTesting
final ExecutorService ioExecutorFromConstructor;
@Inject
public ExecutorServiceModule(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads,
@ -107,7 +109,7 @@ public class ExecutorServiceModule extends AbstractModule {
@Named(Constants.PROPERTY_USER_THREADS)
ExecutorService provideExecutorService(@Named(Constants.PROPERTY_USER_THREADS) int count, Closer closer) {
if (userExecutorFromConstructor != null)
return shutdownOnClose(userExecutorFromConstructor, closer);
return userExecutorFromConstructor;
return shutdownOnClose(newThreadPoolNamed("user thread %d", count), closer);
}
@ -116,7 +118,7 @@ public class ExecutorServiceModule extends AbstractModule {
@Named(Constants.PROPERTY_IO_WORKER_THREADS)
ExecutorService provideIOExecutor(@Named(Constants.PROPERTY_IO_WORKER_THREADS) int count, Closer closer) {
if (ioExecutorFromConstructor != null)
return shutdownOnClose(ioExecutorFromConstructor, closer);
return ioExecutorFromConstructor;
return shutdownOnClose(newThreadPoolNamed("i/o thread %d", count), closer);
}

View File

@ -23,15 +23,20 @@ import java.io.Closeable;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.inject.Singleton;
import com.google.common.collect.Lists;
/**
* This will close objects in the reverse order that they were added.
*
* @author Adrian Cole
*/
@Singleton
public class Closer implements Closeable {
List<Closeable> methodsToClose = new CopyOnWriteArrayList<Closeable>();
// guice is single threaded. no need to lock this
List<Closeable> methodsToClose = Lists.<Closeable> newArrayList();
public void addToClose(Closeable toClose) {
methodsToClose.add(toClose);

View File

@ -19,16 +19,24 @@
package org.jclouds.concurrent.config;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.jclouds.Constants;
import org.jclouds.lifecycle.Closer;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.name.Names;
/**
*
@ -37,20 +45,53 @@ import com.google.inject.Injector;
@Test
public class ExecutorServiceModuleTest {
private Closer closer;
@BeforeTest
public void setUp() throws Exception {
@Test
public void testShutdownOnClose() throws IOException {
Injector i = Guice.createInjector();
closer = i.getInstance(Closer.class);
Closer closer = i.getInstance(Closer.class);
ExecutorService executor = createMock(ExecutorService.class);
ExecutorServiceModule.shutdownOnClose(executor, closer);
expect(executor.shutdownNow()).andReturn(ImmutableList.<Runnable> of()).atLeastOnce();
replay(executor);
closer.close();
verify(executor);
}
@Test
public void testShutdownOnClose() throws IOException {
ExecutorService executor = Executors.newCachedThreadPool();
assert !executor.isShutdown();
ExecutorServiceModule.shutdownOnClose(executor, closer);
public void testShutdownOnCloseThroughModule() throws IOException {
ExecutorServiceModule module = new ExecutorServiceModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Names.named(Constants.PROPERTY_IO_WORKER_THREADS)).to(1);
bindConstant().annotatedWith(Names.named(Constants.PROPERTY_USER_THREADS)).to(1);
super.configure();
}
};
Injector i = Guice.createInjector(module);
assertEquals(module.userExecutorFromConstructor, null);
assertEquals(module.ioExecutorFromConstructor, null);
Closer closer = i.getInstance(Closer.class);
ExecutorService user = i
.getInstance(Key.get(ExecutorService.class, Names.named(Constants.PROPERTY_USER_THREADS)));
ExecutorService io = i.getInstance(Key.get(ExecutorService.class, Names
.named(Constants.PROPERTY_IO_WORKER_THREADS)));
assert !user.isShutdown();
assert !io.isShutdown();
closer.close();
assert executor.isShutdown();
assert user.isShutdown();
assert io.isShutdown();
}
}