Java tutorial
/* * Copyright 2002-2012 the original author or authors. * * 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.green.code.async.executor; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import org.springframework.core.task.TaskRejectedException; import org.springframework.scheduling.SchedulingTaskExecutor; import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; import org.springframework.scheduling.concurrent.ExecutorConfigurationSupport; import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean; import org.springframework.util.Assert; /** * Based on @{link org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor}, * I used my custom {@link org.green.code.async.executor.ThreadPoolExecutor} in initializeExecutor method. */ @SuppressWarnings("serial") public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport implements SchedulingTaskExecutor { private final Object poolSizeMonitor = new Object(); private int corePoolSize = 1; private int maxPoolSize = Integer.MAX_VALUE; private int keepAliveSeconds = 60; private boolean allowCoreThreadTimeOut = false; private int queueCapacity = Integer.MAX_VALUE; private ThreadPoolExecutor threadPoolExecutor; /** * Set the ThreadPoolExecutor's core pool size. Default is 1. * <p> * <b>This setting can be modified at runtime, for example through JMX.</b> */ public void setCorePoolSize(int corePoolSize) { synchronized (this.poolSizeMonitor) { this.corePoolSize = corePoolSize; if (this.threadPoolExecutor != null) { this.threadPoolExecutor.setCorePoolSize(corePoolSize); } } } /** * Return the ThreadPoolExecutor's core pool size. */ public int getCorePoolSize() { synchronized (this.poolSizeMonitor) { return this.corePoolSize; } } /** * Set the ThreadPoolExecutor's maximum pool size. Default is * {@code Integer.MAX_VALUE}. * <p> * <b>This setting can be modified at runtime, for example through JMX.</b> */ public void setMaxPoolSize(int maxPoolSize) { synchronized (this.poolSizeMonitor) { this.maxPoolSize = maxPoolSize; if (this.threadPoolExecutor != null) { this.threadPoolExecutor.setMaximumPoolSize(maxPoolSize); } } } /** * Return the ThreadPoolExecutor's maximum pool size. */ public int getMaxPoolSize() { synchronized (this.poolSizeMonitor) { return this.maxPoolSize; } } /** * Set the ThreadPoolExecutor's keep-alive seconds. Default is 60. * <p> * <b>This setting can be modified at runtime, for example through JMX.</b> */ public void setKeepAliveSeconds(int keepAliveSeconds) { synchronized (this.poolSizeMonitor) { this.keepAliveSeconds = keepAliveSeconds; if (this.threadPoolExecutor != null) { this.threadPoolExecutor.setKeepAliveTime(keepAliveSeconds, TimeUnit.SECONDS); } } } /** * Return the ThreadPoolExecutor's keep-alive seconds. */ public int getKeepAliveSeconds() { synchronized (this.poolSizeMonitor) { return this.keepAliveSeconds; } } /** * Specify whether to allow core threads to time out. This enables dynamic * growing and shrinking even in combination with a non-zero queue (since * the max pool size will only grow once the queue is full). * <p> * Default is "false". Note that this feature is only available on Java 6 or * above. On Java 5, consider switching to the backport-concurrent version * of ThreadPoolTaskExecutor which also supports this feature. * * @see java.util.concurrent.ThreadPoolExecutor#allowCoreThreadTimeOut(boolean) */ public void setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) { this.allowCoreThreadTimeOut = allowCoreThreadTimeOut; } /** * Set the capacity for the ThreadPoolExecutor's BlockingQueue. Default is * {@code Integer.MAX_VALUE}. * <p> * Any positive value will lead to a LinkedBlockingQueue instance; any other * value will lead to a SynchronousQueue instance. * * @see java.util.concurrent.LinkedBlockingQueue * @see java.util.concurrent.SynchronousQueue */ public void setQueueCapacity(int queueCapacity) { this.queueCapacity = queueCapacity; } protected ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { BlockingQueue<Runnable> queue = createQueue(this.queueCapacity); // I am using my custom ThreadPoolExecutor ThreadPoolExecutor executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler); if (this.allowCoreThreadTimeOut) { executor.allowCoreThreadTimeOut(true); } this.threadPoolExecutor = executor; return executor; } /** * Create the BlockingQueue to use for the ThreadPoolExecutor. * <p> * A LinkedBlockingQueue instance will be created for a positive capacity * value; a SynchronousQueue else. * * @param queueCapacity * the specified queue capacity * @return the BlockingQueue instance * @see java.util.concurrent.LinkedBlockingQueue * @see java.util.concurrent.SynchronousQueue */ protected BlockingQueue<Runnable> createQueue(int queueCapacity) { if (queueCapacity > 0) { return new LinkedBlockingQueue<Runnable>(queueCapacity); } else { return new SynchronousQueue<Runnable>(); } } /** * Return the underlying ThreadPoolExecutor for native access. * * @return the underlying ThreadPoolExecutor (never {@code null}) * @throws IllegalStateException * if the ThreadPoolTaskExecutor hasn't been initialized yet */ public ThreadPoolExecutor getThreadPoolExecutor() throws IllegalStateException { Assert.state(this.threadPoolExecutor != null, "ThreadPoolTaskExecutor not initialized"); return this.threadPoolExecutor; } /** * Return the current pool size. * * @see java.util.concurrent.ThreadPoolExecutor#getPoolSize() */ public int getPoolSize() { return getThreadPoolExecutor().getPoolSize(); } /** * Return the number of currently active threads. * * @see java.util.concurrent.ThreadPoolExecutor#getActiveCount() */ public int getActiveCount() { return getThreadPoolExecutor().getActiveCount(); } public void execute(Runnable task) { Executor executor = getThreadPoolExecutor(); try { executor.execute(task); } catch (RejectedExecutionException ex) { throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); } } public void execute(Runnable task, long startTimeout) { execute(task); } public Future<?> submit(Runnable task) { ExecutorService executor = getThreadPoolExecutor(); try { return executor.submit(task); } catch (RejectedExecutionException ex) { throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); } } public <T> Future<T> submit(Callable<T> task) { ExecutorService executor = getThreadPoolExecutor(); try { return executor.submit(task); } catch (RejectedExecutionException ex) { throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); } } /** * This task executor prefers short-lived work units. */ public boolean prefersShortLivedTasks() { return true; } }