001/* 002 * ModeShape (http://www.modeshape.org) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.modeshape.common.util; 017 018import java.util.concurrent.ConcurrentHashMap; 019import java.util.concurrent.ConcurrentMap; 020import java.util.concurrent.ExecutorService; 021import java.util.concurrent.Executors; 022import java.util.concurrent.ScheduledExecutorService; 023import java.util.concurrent.SynchronousQueue; 024import java.util.concurrent.ThreadPoolExecutor; 025import java.util.concurrent.TimeUnit; 026import java.util.function.Predicate; 027import org.modeshape.common.annotation.ThreadSafe; 028 029/** 030 * A simple {@link ThreadPoolFactory} implementation. 031 */ 032@ThreadSafe 033public class ThreadPools implements ThreadPoolFactory { 034 035 private static final int DEFAULT_MAX_THREAD_COUNT = 4; 036 private static final int DEFAULT_SCHEDULED_THREAD_COUNT = 1; 037 038 private final ConcurrentMap<String, ExecutorService> poolsByName = new ConcurrentHashMap<String, ExecutorService>(); 039 040 @Override 041 public ExecutorService getThreadPool( String name ) { 042 return getOrCreateNewPool(name, Executors.newFixedThreadPool(DEFAULT_MAX_THREAD_COUNT, new NamedThreadFactory(name))); 043 } 044 045 @Override 046 public ExecutorService getCachedTreadPool( String name, int maxPoolSize ) { 047 NamedThreadFactory threadFactory = new NamedThreadFactory(name); 048 ExecutorService executorService = new ThreadPoolExecutor(0, maxPoolSize, 60L, TimeUnit.SECONDS, 049 new SynchronousQueue<Runnable>(), 050 threadFactory); 051 return getOrCreateNewPool(name, executorService); 052 } 053 054 @Override 055 public ScheduledExecutorService getScheduledThreadPool( String name ) { 056 return (ScheduledExecutorService)getOrCreateNewPool(name, 057 Executors.newScheduledThreadPool(DEFAULT_SCHEDULED_THREAD_COUNT, 058 new NamedThreadFactory(name))); 059 } 060 061 private ExecutorService getOrCreateNewPool( String name, 062 ExecutorService executorService ) { 063 ExecutorService executor = poolsByName.get(name); 064 if (executor == null) { 065 executor = poolsByName.putIfAbsent(name, executorService); 066 if (executor != null) { 067 // There was an existing one created since we originally checked, so shut down the new executor we just created 068 executor.shutdownNow(); 069 } 070 executor = executorService; 071 } 072 return executor; 073 } 074 075 @Override 076 public void releaseThreadPool( ExecutorService executor ) { 077 for (String executorServiceName : poolsByName.keySet()) { 078 ExecutorService executorService = poolsByName.get(executorServiceName); 079 if (executor.equals(executorService)) { 080 executorService.shutdown(); 081 return; 082 } 083 } 084 } 085 086 @Override 087 public void terminateAllPools( long maxWaitTime, TimeUnit unit ) { 088 poolsByName.values().stream() 089 .filter(((Predicate<ExecutorService>) ExecutorService::isShutdown).negate()) 090 .forEach(executorService -> { 091 executorService.shutdown(); 092 try { 093 if (maxWaitTime > 0) { 094 executorService.awaitTermination(maxWaitTime, unit); 095 } 096 executorService.shutdownNow(); 097 } catch (InterruptedException e) { 098 if (Thread.interrupted()) { 099 executorService.shutdownNow(); 100 } 101 } 102 }); 103 poolsByName.clear(); 104 } 105}