/*
* ModeShape (http://www.modeshape.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.modeshape.common.util;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import org.modeshape.common.annotation.ThreadSafe;
/**
* A simple {@link ThreadPoolFactory} implementation.
*/
@ThreadSafe
public class ThreadPools implements ThreadPoolFactory {
private static final int DEFAULT_MAX_THREAD_COUNT = 4;
private static final int DEFAULT_SCHEDULED_THREAD_COUNT = 1;
private final ConcurrentMap<String, ExecutorService> poolsByName = new ConcurrentHashMap<String, ExecutorService>();
@Override
public ExecutorService getThreadPool( String name ) {
return getOrCreateNewPool(name, Executors.newFixedThreadPool(DEFAULT_MAX_THREAD_COUNT, new NamedThreadFactory(name)));
}
@Override
public ExecutorService getCachedTreadPool( String name, int maxPoolSize ) {
NamedThreadFactory threadFactory = new NamedThreadFactory(name);
ExecutorService executorService = new ThreadPoolExecutor(0, maxPoolSize, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
return getOrCreateNewPool(name, executorService);
}
@Override
public ScheduledExecutorService getScheduledThreadPool( String name ) {
return (ScheduledExecutorService)getOrCreateNewPool(name,
Executors.newScheduledThreadPool(DEFAULT_SCHEDULED_THREAD_COUNT,
new NamedThreadFactory(name)));
}
private ExecutorService getOrCreateNewPool( String name,
ExecutorService executorService ) {
ExecutorService executor = poolsByName.get(name);
if (executor == null) {
executor = poolsByName.putIfAbsent(name, executorService);
if (executor != null) {
// There was an existing one created since we originally checked, so shut down the new executor we just created
executor.shutdownNow();
}
executor = executorService;
}
return executor;
}
@Override
public void releaseThreadPool( ExecutorService executor ) {
for (String executorServiceName : poolsByName.keySet()) {
ExecutorService executorService = poolsByName.get(executorServiceName);
if (executor.equals(executorService)) {
executorService.shutdown();
return;
}
}
}
@Override
public void terminateAllPools( long maxWaitTime, TimeUnit unit ) {
poolsByName.values().stream()
.filter(((Predicate<ExecutorService>) ExecutorService::isShutdown).negate())
.forEach(executorService -> {
executorService.shutdown();
try {
if (maxWaitTime > 0) {
executorService.awaitTermination(maxWaitTime, unit);
}
executorService.shutdownNow();
} catch (InterruptedException e) {
if (Thread.interrupted()) {
executorService.shutdownNow();
}
}
});
poolsByName.clear();
}
}