Browse Source

added "Future submit(Runnable)" and "Future submit(Callable)" to AsyncTaskExecutor; SchedulingTaskExecutor interface extends AsyncTaskExecutor; added ExecutorServiceAdapter class as a standard wrapper for a Spring TaskExecutor; added ThreadPoolExecutorFactoryBean; reduced backport-concurrent support to TaskExecutor adapters

pull/23217/head
Juergen Hoeller 17 years ago
parent
commit
7e4fb09369
  1. 6
      org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerFactoryBean.java
  2. 23
      org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java
  3. 29
      org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SimpleThreadPoolTaskExecutor.java
  4. 6
      org.springframework.context/src/main/java/org/springframework/scheduling/SchedulingTaskExecutor.java
  5. 32
      org.springframework.context/src/main/java/org/springframework/scheduling/backportconcurrent/ConcurrentTaskExecutor.java
  6. 285
      org.springframework.context/src/main/java/org/springframework/scheduling/backportconcurrent/ScheduledExecutorFactoryBean.java
  7. 202
      org.springframework.context/src/main/java/org/springframework/scheduling/backportconcurrent/ScheduledExecutorTask.java
  8. 27
      org.springframework.context/src/main/java/org/springframework/scheduling/backportconcurrent/ThreadPoolTaskExecutor.java
  9. 4
      org.springframework.context/src/main/java/org/springframework/scheduling/backportconcurrent/package.html
  10. 53
      org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java
  11. 160
      org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java
  12. 122
      org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ScheduledExecutorFactoryBean.java
  13. 184
      org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBean.java
  14. 207
      org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.java
  15. 7
      org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/package.html
  16. 5
      org.springframework.context/src/main/java/org/springframework/scheduling/timer/TimerFactoryBean.java
  17. 33
      org.springframework.context/src/main/java/org/springframework/scheduling/timer/TimerTaskExecutor.java
  18. 281
      org.springframework.context/src/test/java/org/springframework/scheduling/backportconcurrent/ScheduledExecutorFactoryBeanTests.java
  19. 43
      org.springframework.core/src/main/java/org/springframework/core/task/AsyncTaskExecutor.java
  20. 59
      org.springframework.core/src/main/java/org/springframework/core/task/SimpleAsyncTaskExecutor.java
  21. 12
      org.springframework.core/src/main/java/org/springframework/core/task/support/ConcurrentExecutorAdapter.java
  22. 87
      org.springframework.core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java
  23. 110
      org.springframework.core/src/main/java/org/springframework/core/task/support/TaskExecutorAdapter.java
  24. 2
      org.springframework.core/src/main/java/org/springframework/core/task/support/package.html
  25. 15
      org.springframework.core/src/main/java/org/springframework/util/CustomizableThreadCreator.java
  26. 15
      org.springframework.core/src/test/java/org/springframework/core/task/SimpleAsyncTaskExecutorTests.java
  27. 6
      org.springframework.transaction/src/main/java/org/springframework/jca/work/SimpleTaskWorkManager.java
  28. 19
      org.springframework.transaction/src/main/java/org/springframework/jca/work/WorkManagerTaskExecutor.java

6
org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerFactoryBean.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -16,10 +16,8 @@ @@ -16,10 +16,8 @@
package org.springframework.scheduling.commonj;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.naming.NamingException;
import commonj.timers.Timer;
@ -141,7 +139,7 @@ public class TimerManagerFactoryBean extends JndiLocatorSupport @@ -141,7 +139,7 @@ public class TimerManagerFactoryBean extends JndiLocatorSupport
if (this.timerManagerName == null) {
throw new IllegalArgumentException("Either 'timerManager' or 'timerManagerName' must be specified");
}
this.timerManager = (TimerManager) lookup(this.timerManagerName, TimerManager.class);
this.timerManager = lookup(this.timerManagerName, TimerManager.class);
}
if (this.scheduledTimerListeners != null) {

23
org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/WorkManagerTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -17,6 +17,9 @@ @@ -17,6 +17,9 @@
package org.springframework.scheduling.commonj;
import java.util.Collection;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.Callable;
import javax.naming.NamingException;
@ -131,7 +134,7 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport @@ -131,7 +134,7 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
if (this.workManagerName == null) {
throw new IllegalArgumentException("Either 'workManager' or 'workManagerName' must be specified");
}
this.workManager = (WorkManager) lookup(this.workManagerName, WorkManager.class);
this.workManager = lookup(this.workManagerName, WorkManager.class);
}
}
@ -159,6 +162,22 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport @@ -159,6 +162,22 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
}
}
public void execute(Runnable task, long startTimeout) {
execute(task);
}
public Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask<Object>(task, null);
execute(future);
return future;
}
public <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask<T>(task);
execute(future);
return future;
}
/**
* This task executor prefers short-lived work units.
*/

29
org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SimpleThreadPoolTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2006 the original author or authors.
* Copyright 2002-2009 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.
@ -16,6 +16,10 @@ @@ -16,6 +16,10 @@
package org.springframework.scheduling.quartz;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import org.quartz.SchedulerConfigException;
import org.quartz.simpl.SimpleThreadPool;
@ -27,11 +31,10 @@ import org.springframework.util.Assert; @@ -27,11 +31,10 @@ import org.springframework.util.Assert;
/**
* Subclass of Quartz's SimpleThreadPool that implements Spring's
* TaskExecutor interface and listens to Spring lifecycle callbacks.
* {@link org.springframework.core.task.TaskExecutor} interface
* and listens to Spring lifecycle callbacks.
*
* <p>Can be used as a thread-pooling TaskExecutor backend, in particular
* on JDK <= 1.5 (where the JDK ThreadPoolExecutor isn't available yet).
* Can be shared between a Quartz Scheduler (specified as "taskExecutor")
* <p>Can be shared between a Quartz Scheduler (specified as "taskExecutor")
* and other TaskExecutor users, or even used completely independent of
* a Quartz Scheduler (as plain TaskExecutor backend).
*
@ -68,6 +71,22 @@ public class SimpleThreadPoolTaskExecutor extends SimpleThreadPool @@ -68,6 +71,22 @@ public class SimpleThreadPoolTaskExecutor extends SimpleThreadPool
}
}
public void execute(Runnable task, long startTimeout) {
execute(task);
}
public Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask<Object>(task, null);
execute(future);
return future;
}
public <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask<T>(task);
execute(future);
return future;
}
/**
* This task executor prefers short-lived work units.
*/

6
org.springframework.context/src/main/java/org/springframework/scheduling/SchedulingTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
package org.springframework.scheduling;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.task.AsyncTaskExecutor;
/**
* A {@link org.springframework.core.task.TaskExecutor} extension exposing
@ -32,7 +32,7 @@ import org.springframework.core.task.TaskExecutor; @@ -32,7 +32,7 @@ import org.springframework.core.task.TaskExecutor;
* @see org.springframework.core.task.TaskExecutor
* @see org.springframework.scheduling.commonj.WorkManagerTaskExecutor
*/
public interface SchedulingTaskExecutor extends TaskExecutor {
public interface SchedulingTaskExecutor extends AsyncTaskExecutor {
/**
* Does this <code>TaskExecutor</code> prefer short-lived tasks over

32
org.springframework.context/src/main/java/org/springframework/scheduling/backportconcurrent/ConcurrentTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@ -16,6 +16,10 @@ @@ -16,6 +16,10 @@
package org.springframework.scheduling.backportconcurrent;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import edu.emory.mathcs.backport.java.util.concurrent.Executor;
import edu.emory.mathcs.backport.java.util.concurrent.Executors;
import edu.emory.mathcs.backport.java.util.concurrent.RejectedExecutionException;
@ -29,11 +33,12 @@ import org.springframework.scheduling.SchedulingTaskExecutor; @@ -29,11 +33,12 @@ import org.springframework.scheduling.SchedulingTaskExecutor;
* exposes a Spring {@link org.springframework.core.task.TaskExecutor} for it.
*
* <p><b>NOTE:</b> This class implements Spring's
* {@link org.springframework.core.task.TaskExecutor} interface as well as
* {@link org.springframework.core.task.TaskExecutor} interface (and hence implicitly
* the standard Java 5 {@link java.util.concurrent.Executor} interface) as well as
* the JSR-166 {@link edu.emory.mathcs.backport.java.util.concurrent.Executor}
* interface, with the former being the primary interface, the other just
* serving as secondary convenience. For this reason, the exception handling
* follows the TaskExecutor contract rather than the Executor contract, in
* follows the TaskExecutor contract rather than the backport Executor contract, in
* particular regarding the {@link org.springframework.core.task.TaskRejectedException}.
*
* <p>Note that there is a pre-built {@link ThreadPoolTaskExecutor} that allows for
@ -73,10 +78,11 @@ public class ConcurrentTaskExecutor implements SchedulingTaskExecutor, Executor @@ -73,10 +78,11 @@ public class ConcurrentTaskExecutor implements SchedulingTaskExecutor, Executor
setConcurrentExecutor(concurrentExecutor);
}
/**
* Specify the JSR-166 backport concurrent executor to delegate to.
*/
public void setConcurrentExecutor(Executor concurrentExecutor) {
public final void setConcurrentExecutor(Executor concurrentExecutor) {
this.concurrentExecutor =
(concurrentExecutor != null ? concurrentExecutor : Executors.newSingleThreadExecutor());
}
@ -85,7 +91,7 @@ public class ConcurrentTaskExecutor implements SchedulingTaskExecutor, Executor @@ -85,7 +91,7 @@ public class ConcurrentTaskExecutor implements SchedulingTaskExecutor, Executor
* Return the JSR-166 backport concurrent executor that this adapter
* delegates to.
*/
public Executor getConcurrentExecutor() {
public final Executor getConcurrentExecutor() {
return this.concurrentExecutor;
}
@ -104,6 +110,22 @@ public class ConcurrentTaskExecutor implements SchedulingTaskExecutor, Executor @@ -104,6 +110,22 @@ public class ConcurrentTaskExecutor implements SchedulingTaskExecutor, Executor
}
}
public void execute(Runnable task, long startTimeout) {
execute(task);
}
public Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask<Object>(task, null);
execute(future);
return future;
}
public <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask<T>(task);
execute(future);
return future;
}
/**
* This task executor prefers short-lived work units.
*/

285
org.springframework.context/src/main/java/org/springframework/scheduling/backportconcurrent/ScheduledExecutorFactoryBean.java

@ -1,285 +0,0 @@ @@ -1,285 +0,0 @@
/*
* Copyright 2002-2008 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.springframework.scheduling.backportconcurrent;
import edu.emory.mathcs.backport.java.util.concurrent.Executors;
import edu.emory.mathcs.backport.java.util.concurrent.RejectedExecutionHandler;
import edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService;
import edu.emory.mathcs.backport.java.util.concurrent.ScheduledThreadPoolExecutor;
import edu.emory.mathcs.backport.java.util.concurrent.ThreadFactory;
import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.scheduling.support.DelegatingExceptionProofRunnable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* {@link org.springframework.beans.factory.FactoryBean} that sets up
* a JSR-166 backport
* {@link edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService}
* (by default:
* {@link edu.emory.mathcs.backport.java.util.concurrent.ScheduledThreadPoolExecutor}
* as implementation) and exposes it for bean references.
*
* <p>Allows for registration of {@link ScheduledExecutorTask ScheduledExecutorTasks},
* automatically starting the {@link ScheduledExecutorService} on initialization and
* cancelling it on destruction of the context. In scenarios that just require static
* registration of tasks at startup, there is no need to access the
* {@link ScheduledExecutorService} instance itself in application code.
*
* <p>Note that
* {@link edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService}
* uses a {@link Runnable} instance that is shared between repeated executions,
* in contrast to Quartz which instantiates a new Job for each execution.
*
* <p><b>WARNING:</b> {@link Runnable Runnables} submitted via a native
* {@link java.util.concurrent.ScheduledExecutorService} are removed from
* the execution schedule once they throw an exception. If you would prefer
* to continue execution after such an exception, switch this FactoryBean's
* {@link #setContinueScheduledExecutionAfterException "continueScheduledExecutionAfterException"}
* property to "true".
*
* <p>This class is analogous to the
* {@link org.springframework.scheduling.timer.TimerFactoryBean}
* class for the JDK {@link java.util.Timer} facility.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see ScheduledExecutorTask
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledThreadPoolExecutor
* @see org.springframework.scheduling.timer.TimerFactoryBean
*/
public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware, InitializingBean, DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
private int poolSize = 1;
private ThreadFactory threadFactory = Executors.defaultThreadFactory();
private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
private boolean exposeUnconfigurableExecutor = false;
private ScheduledExecutorTask[] scheduledExecutorTasks;
private boolean continueScheduledExecutionAfterException = false;
private boolean waitForTasksToCompleteOnShutdown = false;
private String beanName;
private ScheduledExecutorService executor;
/**
* Set the ScheduledExecutorService's pool size.
* Default is 1.
*/
public void setPoolSize(int poolSize) {
Assert.isTrue(poolSize > 0, "'poolSize' must be 1 or higher");
this.poolSize = poolSize;
}
/**
* Set the ThreadFactory to use for the ThreadPoolExecutor's thread pool.
* Default is the ThreadPoolExecutor's default thread factory.
* @see edu.emory.mathcs.backport.java.util.concurrent.Executors#defaultThreadFactory()
*/
public void setThreadFactory(ThreadFactory threadFactory) {
this.threadFactory = (threadFactory != null ? threadFactory : Executors.defaultThreadFactory());
}
/**
* Set the RejectedExecutionHandler to use for the ThreadPoolExecutor.
* Default is the ThreadPoolExecutor's default abort policy.
* @see edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor.AbortPolicy
*/
public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) {
this.rejectedExecutionHandler =
(rejectedExecutionHandler != null ? rejectedExecutionHandler : new ThreadPoolExecutor.AbortPolicy());
}
/**
* Specify whether this FactoryBean should expose an unconfigurable
* decorator for the created executor.
* <p>Default is "false", exposing the raw executor as bean reference.
* Switch this flag to "true" to strictly prevent clients from
* modifying the executor's configuration.
* @see edu.emory.mathcs.backport.java.util.concurrent.Executors#unconfigurableScheduledExecutorService
*/
public void setExposeUnconfigurableExecutor(boolean exposeUnconfigurableExecutor) {
this.exposeUnconfigurableExecutor = exposeUnconfigurableExecutor;
}
/**
* Register a list of ScheduledExecutorTask objects with the ScheduledExecutorService
* that this FactoryBean creates. Depending on each ScheduledExecutorTask's settings,
* it will be registered via one of ScheduledExecutorService's schedule methods.
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#schedule(java.lang.Runnable, long, edu.emory.mathcs.backport.java.util.concurrent.TimeUnit)
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#scheduleWithFixedDelay(java.lang.Runnable, long, long, edu.emory.mathcs.backport.java.util.concurrent.TimeUnit)
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#scheduleAtFixedRate(java.lang.Runnable, long, long, edu.emory.mathcs.backport.java.util.concurrent.TimeUnit)
*/
public void setScheduledExecutorTasks(ScheduledExecutorTask[] scheduledExecutorTasks) {
this.scheduledExecutorTasks = scheduledExecutorTasks;
}
/**
* Specify whether to continue the execution of a scheduled task
* after it threw an exception.
* <p>Default is "false", matching the native behavior of a
* {@link edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService}.
* Switch this flag to "true" for exception-proof execution of each task,
* continuing scheduled execution as in the case of successful execution.
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#scheduleAtFixedRate
*/
public void setContinueScheduledExecutionAfterException(boolean continueScheduledExecutionAfterException) {
this.continueScheduledExecutionAfterException = continueScheduledExecutionAfterException;
}
/**
* Set whether to wait for scheduled tasks to complete on shutdown.
* <p>Default is "false". Switch this to "true" if you prefer
* fully completed tasks at the expense of a longer shutdown phase.
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#shutdown()
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#shutdownNow()
*/
public void setWaitForTasksToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {
this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
}
public void setBeanName(String name) {
this.beanName = name;
}
public void afterPropertiesSet() {
if (logger.isInfoEnabled()) {
logger.info("Initializing ScheduledExecutorService" +
(this.beanName != null ? " '" + this.beanName + "'" : ""));
}
ScheduledExecutorService executor =
createExecutor(this.poolSize, this.threadFactory, this.rejectedExecutionHandler);
// Register specified ScheduledExecutorTasks, if necessary.
if (!ObjectUtils.isEmpty(this.scheduledExecutorTasks)) {
registerTasks(this.scheduledExecutorTasks, executor);
}
// Wrap executor with an unconfigurable decorator.
this.executor = (this.exposeUnconfigurableExecutor ?
Executors.unconfigurableScheduledExecutorService(executor) : executor);
}
/**
* Create a new {@link ScheduledExecutorService} instance.
* Called by <code>afterPropertiesSet</code>.
* <p>The default implementation creates a {@link ScheduledThreadPoolExecutor}.
* Can be overridden in subclasses to provide custom
* {@link ScheduledExecutorService} instances.
* @param poolSize the specified pool size
* @param threadFactory the ThreadFactory to use
* @param rejectedExecutionHandler the RejectedExecutionHandler to use
* @return a new ScheduledExecutorService instance
* @see #afterPropertiesSet()
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledThreadPoolExecutor
*/
protected ScheduledExecutorService createExecutor(
int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
return new ScheduledThreadPoolExecutor(poolSize, threadFactory, rejectedExecutionHandler);
}
/**
* Register the specified {@link ScheduledExecutorTask ScheduledExecutorTasks}
* on the given {@link ScheduledExecutorService}.
* @param tasks the specified ScheduledExecutorTasks (never empty)
* @param executor the ScheduledExecutorService to register the tasks on.
*/
protected void registerTasks(ScheduledExecutorTask[] tasks, ScheduledExecutorService executor) {
for (int i = 0; i < tasks.length; i++) {
ScheduledExecutorTask task = tasks[i];
Runnable runnable = getRunnableToSchedule(task);
if (task.isOneTimeTask()) {
executor.schedule(runnable, task.getDelay(), task.getTimeUnit());
}
else {
if (task.isFixedRate()) {
executor.scheduleAtFixedRate(runnable, task.getDelay(), task.getPeriod(), task.getTimeUnit());
}
else {
executor.scheduleWithFixedDelay(runnable, task.getDelay(), task.getPeriod(), task.getTimeUnit());
}
}
}
}
/**
* Determine the actual Runnable to schedule for the given task.
* <p>Wraps the task's Runnable in a
* {@link org.springframework.scheduling.support.DelegatingExceptionProofRunnable}
* if necessary, according to the
* {@link #setContinueScheduledExecutionAfterException "continueScheduledExecutionAfterException"}
* flag.
* @param task the ScheduledExecutorTask to schedule
* @return the actual Runnable to schedule (may be a decorator)
*/
protected Runnable getRunnableToSchedule(ScheduledExecutorTask task) {
boolean propagateException = !this.continueScheduledExecutionAfterException;
return new DelegatingExceptionProofRunnable(task.getRunnable(), propagateException);
}
public Object getObject() {
return this.executor;
}
public Class getObjectType() {
return (this.executor != null ? this.executor.getClass() : ScheduledExecutorService.class);
}
public boolean isSingleton() {
return true;
}
/**
* Cancel the ScheduledExecutorService on bean factory shutdown,
* stopping all scheduled tasks.
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#shutdown()
*/
public void destroy() {
if (logger.isInfoEnabled()) {
logger.info("Shutting down ScheduledExecutorService" +
(this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (this.waitForTasksToCompleteOnShutdown) {
this.executor.shutdown();
}
else {
this.executor.shutdownNow();
}
}
}

202
org.springframework.context/src/main/java/org/springframework/scheduling/backportconcurrent/ScheduledExecutorTask.java

@ -1,202 +0,0 @@ @@ -1,202 +0,0 @@
/*
* Copyright 2002-2007 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.springframework.scheduling.backportconcurrent;
import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
/**
* JavaBean that describes a scheduled executor task, consisting of the
* {@link Runnable} and a delay plus period. The period needs to be specified;
* there is no point in a default for it.
*
* <p>The JSR-166 backport
* {@link edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService}
* does not offer more sophisticated scheduling options such as cron expressions.
* Consider using Quartz for such advanced needs.
*
* <p>Note that the
* {@link edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService}
* mechanism uses a {@link Runnable} instance that is shared between repeated executions,
* in contrast to Quartz which creates a new Job instance for each execution.
*
* <p>This class is analogous to the {@link org.springframework.scheduling.timer.ScheduledTimerTask}
* class for the JDK {@link java.util.Timer} facility.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#scheduleWithFixedDelay(java.lang.Runnable, long, long, edu.emory.mathcs.backport.java.util.concurrent.TimeUnit)
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#scheduleAtFixedRate(java.lang.Runnable, long, long, edu.emory.mathcs.backport.java.util.concurrent.TimeUnit)
* @see org.springframework.scheduling.timer.ScheduledTimerTask
*/
public class ScheduledExecutorTask {
private Runnable runnable;
private long delay = 0;
private long period = -1;
private TimeUnit timeUnit = TimeUnit.MILLISECONDS;
private boolean fixedRate = false;
/**
* Create a new ScheduledExecutorTask,
* to be populated via bean properties.
* @see #setDelay
* @see #setPeriod
* @see #setFixedRate
*/
public ScheduledExecutorTask() {
}
/**
* Create a new ScheduledExecutorTask, with default
* one-time execution without delay.
* @param executorTask the Runnable to schedule
*/
public ScheduledExecutorTask(Runnable executorTask) {
this.runnable = executorTask;
}
/**
* Create a new ScheduledExecutorTask, with default
* one-time execution with the given delay.
* @param executorTask the Runnable to schedule
* @param delay the delay before starting the task for the first time (ms)
*/
public ScheduledExecutorTask(Runnable executorTask, long delay) {
this.runnable = executorTask;
this.delay = delay;
}
/**
* Create a new ScheduledExecutorTask.
* @param executorTask the Runnable to schedule
* @param delay the delay before starting the task for the first time (ms)
* @param period the period between repeated task executions (ms)
* @param fixedRate whether to schedule as fixed-rate execution
*/
public ScheduledExecutorTask(Runnable executorTask, long delay, long period, boolean fixedRate) {
this.runnable = executorTask;
this.delay = delay;
this.period = period;
this.fixedRate = fixedRate;
}
/**
* Set the Runnable to schedule as executor task.
*/
public void setRunnable(Runnable executorTask) {
this.runnable = executorTask;
}
/**
* Return the Runnable to schedule as executor task.
*/
public Runnable getRunnable() {
return this.runnable;
}
/**
* Set the delay before starting the task for the first time,
* in milliseconds. Default is 0, immediately starting the
* task after successful scheduling.
*/
public void setDelay(long delay) {
this.delay = delay;
}
/**
* Return the delay before starting the job for the first time.
*/
public long getDelay() {
return this.delay;
}
/**
* Set the period between repeated task executions, in milliseconds.
* <p>Default is -1, leading to one-time execution. In case of a positive value,
* the task will be executed repeatedly, with the given interval inbetween executions.
* <p>Note that the semantics of the period value vary between fixed-rate and
* fixed-delay execution.
* <p><b>Note:</b> A period of 0 (for example as fixed delay) is <i>not</i> supported,
* simply because <code>edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService</code> itself
* does not support it. Hence a value of 0 will be treated as one-time execution;
* however, that value should never be specified explicitly in the first place!
* @see #setFixedRate
* @see #isOneTimeTask()
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#scheduleWithFixedDelay(java.lang.Runnable, long, long, edu.emory.mathcs.backport.java.util.concurrent.TimeUnit)
*/
public void setPeriod(long period) {
this.period = period;
}
/**
* Return the period between repeated task executions.
*/
public long getPeriod() {
return this.period;
}
/**
* Is this task only ever going to execute once?
* @return <code>true</code> if this task is only ever going to execute once
* @see #getPeriod()
*/
public boolean isOneTimeTask() {
return (this.period <= 0);
}
/**
* Specify the time unit for the delay and period values.
* Default is milliseconds (<code>TimeUnit.MILLISECONDS</code>).
* @see edu.emory.mathcs.backport.java.util.concurrent.TimeUnit#MILLISECONDS
* @see edu.emory.mathcs.backport.java.util.concurrent.TimeUnit#SECONDS
*/
public void setTimeUnit(TimeUnit timeUnit) {
this.timeUnit = (timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS);
}
/**
* Return the time unit for the delay and period values.
*/
public TimeUnit getTimeUnit() {
return this.timeUnit;
}
/**
* Set whether to schedule as fixed-rate execution, rather than
* fixed-delay execution. Default is "false", that is, fixed delay.
* <p>See ScheduledExecutorService javadoc for details on those execution modes.
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#scheduleWithFixedDelay(java.lang.Runnable, long, long, edu.emory.mathcs.backport.java.util.concurrent.TimeUnit)
* @see edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService#scheduleAtFixedRate(java.lang.Runnable, long, long, edu.emory.mathcs.backport.java.util.concurrent.TimeUnit)
*/
public void setFixedRate(boolean fixedRate) {
this.fixedRate = fixedRate;
}
/**
* Return whether to schedule as fixed-rate execution.
*/
public boolean isFixedRate() {
return this.fixedRate;
}
}

27
org.springframework.context/src/main/java/org/springframework/scheduling/backportconcurrent/ThreadPoolTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -16,6 +16,10 @@ @@ -16,6 +16,10 @@
package org.springframework.scheduling.backportconcurrent;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue;
import edu.emory.mathcs.backport.java.util.concurrent.Executor;
import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
@ -52,11 +56,12 @@ import org.springframework.util.Assert; @@ -52,11 +56,12 @@ import org.springframework.util.Assert;
* simply wrap it with a {@link ConcurrentTaskExecutor} adapter.
*
* <p><b>NOTE:</b> This class implements Spring's
* {@link org.springframework.core.task.TaskExecutor} interface as well as
* {@link org.springframework.core.task.TaskExecutor} interface (and hence implicitly
* the standard Java 5 {@link java.util.concurrent.Executor} interface) as well as
* the JSR-166 {@link edu.emory.mathcs.backport.java.util.concurrent.Executor}
* interface, with the former being the primary interface, the other just
* serving as secondary convenience. For this reason, the exception handling
* follows the TaskExecutor contract rather than the Executor contract, in
* follows the TaskExecutor contract rather than the backport Executor contract, in
* particular regarding the {@link org.springframework.core.task.TaskRejectedException}.
*
* @author Juergen Hoeller
@ -308,6 +313,22 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory @@ -308,6 +313,22 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory
}
}
public void execute(Runnable task, long startTimeout) {
execute(task);
}
public Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask<Object>(task, null);
execute(future);
return future;
}
public <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask<T>(task);
execute(future);
return future;
}
/**
* This task executor prefers short-lived work units.
*/

4
org.springframework.context/src/main/java/org/springframework/scheduling/backportconcurrent/package.html

@ -3,8 +3,8 @@ @@ -3,8 +3,8 @@
Scheduling convenience classes for the
<a href="http://dcl.mathcs.emory.edu/util/backport-util-concurrent/">JSR-166 backport</a>
Executor mechanism, allowing to set up a ThreadPoolExecutor or
ScheduledThreadPoolExecutor as bean in a Spring context.
Executor mechanism, allowing to set up a ThreadPoolExecutor
as a TaskExecutor-compliant bean in a Spring context.
</body>
</html>

53
org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@ -16,23 +16,23 @@ @@ -16,23 +16,23 @@
package org.springframework.scheduling.concurrent;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RejectedExecutionException;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.scheduling.SchedulingTaskExecutor;
/**
* Adapter that takes a JDK 1.5 <code>java.util.concurrent.Executor</code> and
* exposes a Spring {@link org.springframework.core.task.TaskExecutor} for it.
*
* <p><b>NOTE:</b> This class implements Spring's
* {@link org.springframework.core.task.TaskExecutor} interface as well as the JDK 1.5
* {@link java.util.concurrent.Executor} interface, with the former being the primary
* interface, the other just serving as secondary convenience. For this reason, the
* exception handling follows the TaskExecutor contract rather than the Executor contract,
* in particular regarding the {@link org.springframework.core.task.TaskRejectedException}.
* Also detects an extended <code>java.util.concurrent.ExecutorService</code>, adapting
* the {@link org.springframework.core.task.AsyncTaskExecutor} interface accordingly.
*
* <p>Note that there is a pre-built {@link ThreadPoolTaskExecutor} that allows for
* defining a JDK 1.5 {@link java.util.concurrent.ThreadPoolExecutor} in bean style,
@ -43,14 +43,17 @@ import org.springframework.scheduling.SchedulingTaskExecutor; @@ -43,14 +43,17 @@ import org.springframework.scheduling.SchedulingTaskExecutor;
* @author Juergen Hoeller
* @since 2.0
* @see java.util.concurrent.Executor
* @see java.util.concurrent.ExecutorService
* @see java.util.concurrent.ThreadPoolExecutor
* @see java.util.concurrent.Executors
* @see ThreadPoolTaskExecutor
*/
public class ConcurrentTaskExecutor implements SchedulingTaskExecutor, Executor {
public class ConcurrentTaskExecutor implements SchedulingTaskExecutor {
private Executor concurrentExecutor;
private TaskExecutorAdapter adaptedExecutor;
/**
* Create a new ConcurrentTaskExecutor,
@ -74,32 +77,34 @@ public class ConcurrentTaskExecutor implements SchedulingTaskExecutor, Executor @@ -74,32 +77,34 @@ public class ConcurrentTaskExecutor implements SchedulingTaskExecutor, Executor
/**
* Specify the JDK 1.5 concurrent executor to delegate to.
*/
public void setConcurrentExecutor(Executor concurrentExecutor) {
public final void setConcurrentExecutor(Executor concurrentExecutor) {
this.concurrentExecutor =
(concurrentExecutor != null ? concurrentExecutor : Executors.newSingleThreadExecutor());
this.adaptedExecutor = new TaskExecutorAdapter(this.concurrentExecutor);
}
/**
* Return the JDK 1.5 concurrent executor that this adapter
* delegates to.
* Return the JDK 1.5 concurrent executor that this adapter delegates to.
*/
public Executor getConcurrentExecutor() {
public final Executor getConcurrentExecutor() {
return this.concurrentExecutor;
}
/**
* Delegates to the specified JDK 1.5 concurrent executor.
* @see java.util.concurrent.Executor#execute(Runnable)
*/
public void execute(Runnable task) {
try {
this.concurrentExecutor.execute(task);
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException(
"Executor [" + this.concurrentExecutor + "] did not accept task: " + task, ex);
}
this.adaptedExecutor.execute(task);
}
public void execute(Runnable task, long startTimeout) {
this.adaptedExecutor.execute(task, startTimeout);
}
public Future<?> submit(Runnable task) {
return this.adaptedExecutor.submit(task);
}
public <T> Future<T> submit(Callable<T> task) {
return this.adaptedExecutor.submit(task);
}
/**

160
org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java

@ -0,0 +1,160 @@ @@ -0,0 +1,160 @@
/*
* Copyright 2002-2009 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.springframework.scheduling.concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
* Base class for classes that are setting up a
* <code>java.util.concurrent.ExecutorService</code>
* (typically a {@link java.util.concurrent.ThreadPoolExecutor}).
* Defines common configuration settings and common lifecycle handling.
*
* @author Juergen Hoeller
* @since 3.0
* @see java.util.concurrent.ExecutorService
* @see java.util.concurrent.Executors
* @see java.util.concurrent.ThreadPoolExecutor
*/
public abstract class ExecutorConfigurationSupport extends CustomizableThreadFactory
implements BeanNameAware, InitializingBean, DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
private ThreadFactory threadFactory = this;
private boolean threadNamePrefixSet = false;
private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
private boolean waitForTasksToCompleteOnShutdown = false;
private String beanName;
private ExecutorService executor;
/**
* Set the ThreadFactory to use for the ThreadPoolExecutor's thread pool.
* Default is the ThreadPoolExecutor's default thread factory.
* @see java.util.concurrent.Executors#defaultThreadFactory()
*/
public void setThreadFactory(ThreadFactory threadFactory) {
this.threadFactory = (threadFactory != null ? threadFactory : this);
}
@Override
public void setThreadNamePrefix(String threadNamePrefix) {
super.setThreadNamePrefix(threadNamePrefix);
this.threadNamePrefixSet = true;
}
/**
* Set the RejectedExecutionHandler to use for the ThreadPoolExecutor.
* Default is the ThreadPoolExecutor's default abort policy.
* @see java.util.concurrent.ThreadPoolExecutor.AbortPolicy
*/
public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) {
this.rejectedExecutionHandler =
(rejectedExecutionHandler != null ? rejectedExecutionHandler : new ThreadPoolExecutor.AbortPolicy());
}
/**
* Set whether to wait for scheduled tasks to complete on shutdown.
* <p>Default is "false". Switch this to "true" if you prefer
* fully completed tasks at the expense of a longer shutdown phase.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#shutdownNow()
*/
public void setWaitForTasksToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {
this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
}
public void setBeanName(String name) {
this.beanName = name;
}
/**
* Calls <code>initialize()</code> after the container applied all property values.
* @see #initialize()
*/
public void afterPropertiesSet() {
initialize();
}
/**
* Set up the ExecutorService.
*/
public void initialize() {
if (logger.isInfoEnabled()) {
logger.info("Initializing ExecutorService " + (this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (!this.threadNamePrefixSet && this.beanName != null) {
setThreadNamePrefix(this.beanName + "-");
}
this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);
}
/**
* Create the target {@link java.util.concurrent.ExecutorService} instance.
* Called by <code>afterPropertiesSet</code>.
* @param threadFactory the ThreadFactory to use
* @param rejectedExecutionHandler the RejectedExecutionHandler to use
* @return a new ExecutorService instance
* @see #afterPropertiesSet()
*/
protected abstract ExecutorService initializeExecutor(
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler);
/**
* Calls <code>shutdown</code> when the BeanFactory destroys
* the task executor instance.
* @see #shutdown()
*/
public void destroy() {
shutdown();
}
/**
* Perform a shutdown on the ThreadPoolExecutor.
* @see java.util.concurrent.ExecutorService#shutdown()
*/
public void shutdown() {
if (logger.isInfoEnabled()) {
logger.info("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (this.waitForTasksToCompleteOnShutdown) {
this.executor.shutdown();
}
else {
this.executor.shutdownNow();
}
}
}

122
org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ScheduledExecutorFactoryBean.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -16,17 +16,13 @@ @@ -16,17 +16,13 @@
package org.springframework.scheduling.concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
@ -37,8 +33,8 @@ import org.springframework.util.ObjectUtils; @@ -37,8 +33,8 @@ import org.springframework.util.ObjectUtils;
/**
* {@link org.springframework.beans.factory.FactoryBean} that sets up
* a JDK 1.5 {@link java.util.concurrent.ScheduledExecutorService}
* (by default: {@link java.util.concurrent.ScheduledThreadPoolExecutor}
* as implementation) and exposes it for bean references.
* (by default: a {@link java.util.concurrent.ScheduledThreadPoolExecutor})
* and exposes it for bean references.
*
* <p>Allows for registration of {@link ScheduledExecutorTask ScheduledExecutorTasks},
* automatically starting the {@link ScheduledExecutorService} on initialization and
@ -66,29 +62,19 @@ import org.springframework.util.ObjectUtils; @@ -66,29 +62,19 @@ import org.springframework.util.ObjectUtils;
* @see ScheduledExecutorTask
* @see java.util.concurrent.ScheduledExecutorService
* @see java.util.concurrent.ScheduledThreadPoolExecutor
* @see org.springframework.scheduling.timer.TimerFactoryBean
*/
public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware, InitializingBean, DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
public class ScheduledExecutorFactoryBean extends ExecutorConfigurationSupport
implements FactoryBean<ScheduledExecutorService>, InitializingBean, DisposableBean {
private int poolSize = 1;
private ThreadFactory threadFactory = Executors.defaultThreadFactory();
private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
private boolean exposeUnconfigurableExecutor = false;
private ScheduledExecutorTask[] scheduledExecutorTasks;
private boolean continueScheduledExecutionAfterException = false;
private boolean waitForTasksToCompleteOnShutdown = false;
private String beanName;
private boolean exposeUnconfigurableExecutor = false;
private ScheduledExecutorService executor;
private ScheduledExecutorService exposedExecutor;
/**
@ -100,37 +86,6 @@ public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware, @@ -100,37 +86,6 @@ public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware,
this.poolSize = poolSize;
}
/**
* Set the ThreadFactory to use for the ThreadPoolExecutor's thread pool.
* Default is the ThreadPoolExecutor's default thread factory.
* @see java.util.concurrent.Executors#defaultThreadFactory()
*/
public void setThreadFactory(ThreadFactory threadFactory) {
this.threadFactory = (threadFactory != null ? threadFactory : Executors.defaultThreadFactory());
}
/**
* Set the RejectedExecutionHandler to use for the ThreadPoolExecutor.
* Default is the ThreadPoolExecutor's default abort policy.
* @see java.util.concurrent.ThreadPoolExecutor.AbortPolicy
*/
public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) {
this.rejectedExecutionHandler =
(rejectedExecutionHandler != null ? rejectedExecutionHandler : new ThreadPoolExecutor.AbortPolicy());
}
/**
* Specify whether this FactoryBean should expose an unconfigurable
* decorator for the created executor.
* <p>Default is "false", exposing the raw executor as bean reference.
* Switch this flag to "true" to strictly prevent clients from
* modifying the executor's configuration.
* @see java.util.concurrent.Executors#unconfigurableScheduledExecutorService
*/
public void setExposeUnconfigurableExecutor(boolean exposeUnconfigurableExecutor) {
this.exposeUnconfigurableExecutor = exposeUnconfigurableExecutor;
}
/**
* Register a list of ScheduledExecutorTask objects with the ScheduledExecutorService
* that this FactoryBean creates. Depending on each ScheduledExecutorTask's settings,
@ -157,28 +112,23 @@ public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware, @@ -157,28 +112,23 @@ public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware,
}
/**
* Set whether to wait for scheduled tasks to complete on shutdown.
* <p>Default is "false". Switch this to "true" if you prefer
* fully completed tasks at the expense of a longer shutdown phase.
* @see java.util.concurrent.ScheduledExecutorService#shutdown()
* @see java.util.concurrent.ScheduledExecutorService#shutdownNow()
* Specify whether this FactoryBean should expose an unconfigurable
* decorator for the created executor.
* <p>Default is "false", exposing the raw executor as bean reference.
* Switch this flag to "true" to strictly prevent clients from
* modifying the executor's configuration.
* @see java.util.concurrent.Executors#unconfigurableScheduledExecutorService
*/
public void setWaitForTasksToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {
this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
public void setExposeUnconfigurableExecutor(boolean exposeUnconfigurableExecutor) {
this.exposeUnconfigurableExecutor = exposeUnconfigurableExecutor;
}
public void setBeanName(String name) {
this.beanName = name;
}
protected ExecutorService initializeExecutor(
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
public void afterPropertiesSet() {
if (logger.isInfoEnabled()) {
logger.info("Initializing ScheduledExecutorService" +
(this.beanName != null ? " '" + this.beanName + "'" : ""));
}
ScheduledExecutorService executor =
createExecutor(this.poolSize, this.threadFactory, this.rejectedExecutionHandler);
createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler);
// Register specified ScheduledExecutorTasks, if necessary.
if (!ObjectUtils.isEmpty(this.scheduledExecutorTasks)) {
@ -186,8 +136,10 @@ public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware, @@ -186,8 +136,10 @@ public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware,
}
// Wrap executor with an unconfigurable decorator.
this.executor = (this.exposeUnconfigurableExecutor ?
this.exposedExecutor = (this.exposeUnconfigurableExecutor ?
Executors.unconfigurableScheduledExecutorService(executor) : executor);
return executor;
}
/**
@ -216,8 +168,7 @@ public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware, @@ -216,8 +168,7 @@ public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware,
* @param executor the ScheduledExecutorService to register the tasks on.
*/
protected void registerTasks(ScheduledExecutorTask[] tasks, ScheduledExecutorService executor) {
for (int i = 0; i < tasks.length; i++) {
ScheduledExecutorTask task = tasks[i];
for (ScheduledExecutorTask task : tasks) {
Runnable runnable = getRunnableToSchedule(task);
if (task.isOneTimeTask()) {
executor.schedule(runnable, task.getDelay(), task.getTimeUnit());
@ -249,35 +200,16 @@ public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware, @@ -249,35 +200,16 @@ public class ScheduledExecutorFactoryBean implements FactoryBean, BeanNameAware,
}
public Object getObject() {
return this.executor;
public ScheduledExecutorService getObject() {
return this.exposedExecutor;
}
public Class getObjectType() {
return (this.executor != null ? this.executor.getClass() : ScheduledExecutorService.class);
public Class<? extends ScheduledExecutorService> getObjectType() {
return (this.exposedExecutor != null ? this.exposedExecutor.getClass() : ScheduledExecutorService.class);
}
public boolean isSingleton() {
return true;
}
/**
* Cancel the ScheduledExecutorService on bean factory shutdown,
* stopping all scheduled tasks.
* @see java.util.concurrent.ScheduledExecutorService#shutdown()
*/
public void destroy() {
if (logger.isInfoEnabled()) {
logger.info("Shutting down ScheduledExecutorService" +
(this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (this.waitForTasksToCompleteOnShutdown) {
this.executor.shutdown();
}
else {
this.executor.shutdownNow();
}
}
}

184
org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBean.java

@ -0,0 +1,184 @@ @@ -0,0 +1,184 @@
/*
* Copyright 2002-2009 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.springframework.scheduling.concurrent;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
/**
* JavaBean that allows for configuring a JDK 1.5 {@link java.util.concurrent.ThreadPoolExecutor}
* in bean style (through its "corePoolSize", "maxPoolSize", "keepAliveSeconds",
* "queueCapacity" properties) and exposing it as a bean reference of its native
* {@link java.util.concurrent.ExecutorService} type.
*
* <p>For an alternative, you may set up a ThreadPoolExecutor instance directly using
* constructor injection, or use a factory method definition that points to the JDK 1.5
* {@link java.util.concurrent.Executors} class.
*
* <p><b>If you need a timing-based {@link java.util.concurrent.ScheduledExecutorService}
* instead, consider {@link ScheduledExecutorFactoryBean}.</b>
* @author Juergen Hoeller
* @since 3.0
* @see java.util.concurrent.ExecutorService
* @see java.util.concurrent.Executors
* @see java.util.concurrent.ThreadPoolExecutor
*/
public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport
implements FactoryBean<ExecutorService>, InitializingBean, DisposableBean {
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 boolean exposeUnconfigurableExecutor = false;
private ExecutorService exposedExecutor;
/**
* 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) {
this.corePoolSize = corePoolSize;
}
/**
* Set the ThreadPoolExecutor's maximum pool size.
* Default is <code>Integer.MAX_VALUE</code>.
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
*/
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = 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) {
this.keepAliveSeconds = 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</code>.
* <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;
}
/**
* Specify whether this FactoryBean should expose an unconfigurable
* decorator for the created executor.
* <p>Default is "false", exposing the raw executor as bean reference.
* Switch this flag to "true" to strictly prevent clients from
* modifying the executor's configuration.
* @see java.util.concurrent.Executors#unconfigurableScheduledExecutorService
*/
public void setExposeUnconfigurableExecutor(boolean exposeUnconfigurableExecutor) {
this.exposeUnconfigurableExecutor = exposeUnconfigurableExecutor;
}
protected ExecutorService initializeExecutor(
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
queue, threadFactory, rejectedExecutionHandler);
if (this.allowCoreThreadTimeOut) {
executor.allowCoreThreadTimeOut(true);
}
// Wrap executor with an unconfigurable decorator.
this.exposedExecutor = (this.exposeUnconfigurableExecutor ?
Executors.unconfigurableExecutorService(executor) : 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>();
}
}
public ExecutorService getObject() throws Exception {
return this.exposedExecutor;
}
public Class<? extends ExecutorService> getObjectType() {
return (this.exposedExecutor != null ? this.exposedExecutor.getClass() : ExecutorService.class);
}
public boolean isSingleton() {
return true;
}
}

207
org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -17,7 +17,10 @@ @@ -17,7 +17,10 @@
package org.springframework.scheduling.concurrent;
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;
@ -26,12 +29,6 @@ import java.util.concurrent.ThreadFactory; @@ -26,12 +29,6 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.scheduling.SchedulingTaskExecutor;
import org.springframework.util.Assert;
@ -39,16 +36,16 @@ import org.springframework.util.Assert; @@ -39,16 +36,16 @@ import org.springframework.util.Assert;
/**
* JavaBean that allows for configuring a JDK 1.5 {@link java.util.concurrent.ThreadPoolExecutor}
* in bean style (through its "corePoolSize", "maxPoolSize", "keepAliveSeconds", "queueCapacity"
* properties), exposing it as a Spring {@link org.springframework.core.task.TaskExecutor}.
* This is an alternative to configuring a ThreadPoolExecutor instance directly using
* constructor injection, with a separate {@link ConcurrentTaskExecutor} adapter wrapping it.
* properties) and exposing it as a Spring {@link org.springframework.core.task.TaskExecutor}.
* This class is also well suited for management and monitoring (e.g. through JMX),
* providing several useful attributes: "corePoolSize", "maxPoolSize", "keepAliveSeconds"
* (all supporting updates at runtime); "poolSize", "activeCount" (for introspection only).
*
* <p>For any custom needs, in particular for defining a
* {@link java.util.concurrent.ScheduledThreadPoolExecutor}, it is recommended to
* use a straight definition of the Executor instance or a factory method definition
* that points to the JDK 1.5 {@link java.util.concurrent.Executors} class.
* To expose such a raw Executor as a Spring {@link org.springframework.core.task.TaskExecutor},
* simply wrap it with a {@link ConcurrentTaskExecutor} adapter.
* <p>For an alternative, you may set up a ThreadPoolExecutor instance directly using
* constructor injection, or use a factory method definition that points to the JDK 1.5
* {@link java.util.concurrent.Executors} class. To expose such a raw Executor as a
* Spring {@link org.springframework.core.task.TaskExecutor}, simply wrap it with a
* {@link org.springframework.scheduling.concurrent.ConcurrentTaskExecutor} adapter.
*
* <p><b>NOTE:</b> This class implements Spring's
* {@link org.springframework.core.task.TaskExecutor} interface as well as the JDK 1.5
@ -57,19 +54,16 @@ import org.springframework.util.Assert; @@ -57,19 +54,16 @@ import org.springframework.util.Assert;
* exception handling follows the TaskExecutor contract rather than the Executor contract,
* in particular regarding the {@link org.springframework.core.task.TaskRejectedException}.
*
* <p><b>If you prefer native {@link java.util.concurrent.ExecutorService} exposure instead,
* consider {@link ThreadPoolExecutorFactoryBean} as an alternative to this class.</b>
*
* @author Juergen Hoeller
* @since 2.0
* @see org.springframework.core.task.TaskExecutor
* @see java.util.concurrent.Executor
* @see java.util.concurrent.ThreadPoolExecutor
* @see java.util.concurrent.ScheduledThreadPoolExecutor
* @see java.util.concurrent.Executors
* @see ConcurrentTaskExecutor
*/
public class ThreadPoolTaskExecutor extends CustomizableThreadFactory
implements SchedulingTaskExecutor, Executor, BeanNameAware, InitializingBean, DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport implements SchedulingTaskExecutor {
private final Object poolSizeMonitor = new Object();
@ -83,16 +77,6 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory @@ -83,16 +77,6 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory
private int queueCapacity = Integer.MAX_VALUE;
private ThreadFactory threadFactory = this;
private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy();
private boolean waitForTasksToCompleteOnShutdown = false;
private boolean threadNamePrefixSet = false;
private String beanName;
private ThreadPoolExecutor threadPoolExecutor;
@ -190,76 +174,20 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory @@ -190,76 +174,20 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory
this.queueCapacity = queueCapacity;
}
/**
* Set the ThreadFactory to use for the ThreadPoolExecutor's thread pool.
* <p>Default is this executor itself (i.e. the factory that this executor
* inherits from). See {@link org.springframework.util.CustomizableThreadCreator}'s
* javadoc for available bean properties.
* @see #setThreadPriority
* @see #setDaemon
*/
public void setThreadFactory(ThreadFactory threadFactory) {
this.threadFactory = (threadFactory != null ? threadFactory : this);
}
/**
* Set the RejectedExecutionHandler to use for the ThreadPoolExecutor.
* Default is the ThreadPoolExecutor's default abort policy.
* @see java.util.concurrent.ThreadPoolExecutor.AbortPolicy
*/
public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) {
this.rejectedExecutionHandler =
(rejectedExecutionHandler != null ? rejectedExecutionHandler : new ThreadPoolExecutor.AbortPolicy());
}
/**
* Set whether to wait for scheduled tasks to complete on shutdown.
* <p>Default is "false". Switch this to "true" if you prefer
* fully completed tasks at the expense of a longer shutdown phase.
* @see java.util.concurrent.ThreadPoolExecutor#shutdown()
* @see java.util.concurrent.ThreadPoolExecutor#shutdownNow()
*/
public void setWaitForTasksToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {
this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
}
@Override
public void setThreadNamePrefix(String threadNamePrefix) {
super.setThreadNamePrefix(threadNamePrefix);
this.threadNamePrefixSet = true;
}
public void setBeanName(String name) {
this.beanName = name;
}
/**
* Calls <code>initialize()</code> after the container applied all property values.
* @see #initialize()
*/
public void afterPropertiesSet() {
initialize();
}
protected ExecutorService initializeExecutor(
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
/**
* Creates the BlockingQueue and the ThreadPoolExecutor.
* @see #createQueue
*/
public void initialize() {
if (logger.isInfoEnabled()) {
logger.info("Initializing ThreadPoolExecutor" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (!this.threadNamePrefixSet && this.beanName != null) {
setThreadNamePrefix(this.beanName + "-");
}
BlockingQueue queue = createQueue(this.queueCapacity);
this.threadPoolExecutor = new ThreadPoolExecutor(
BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
queue, this.threadFactory, this.rejectedExecutionHandler);
queue, threadFactory, rejectedExecutionHandler);
if (this.allowCoreThreadTimeOut) {
this.threadPoolExecutor.allowCoreThreadTimeOut(true);
executor.allowCoreThreadTimeOut(true);
}
this.threadPoolExecutor = executor;
return executor;
}
/**
@ -271,12 +199,12 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory @@ -271,12 +199,12 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory
* @see java.util.concurrent.LinkedBlockingQueue
* @see java.util.concurrent.SynchronousQueue
*/
protected BlockingQueue createQueue(int queueCapacity) {
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
if (queueCapacity > 0) {
return new LinkedBlockingQueue(queueCapacity);
return new LinkedBlockingQueue<Runnable>(queueCapacity);
}
else {
return new SynchronousQueue();
return new SynchronousQueue<Runnable>();
}
}
@ -290,6 +218,22 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory @@ -290,6 +218,22 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory
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();
}
/**
* Implementation of both the JDK 1.5 Executor interface and the Spring
@ -307,54 +251,35 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory @@ -307,54 +251,35 @@ public class ThreadPoolTaskExecutor extends CustomizableThreadFactory
}
}
/**
* This task executor prefers short-lived work units.
*/
public boolean prefersShortLivedTasks() {
return true;
}
/**
* Return the current pool size.
* @see java.util.concurrent.ThreadPoolExecutor#getPoolSize()
*/
public int getPoolSize() {
return getThreadPoolExecutor().getPoolSize();
public void execute(Runnable task, long startTimeout) {
execute(task);
}
/**
* Return the number of currently active threads.
* @see java.util.concurrent.ThreadPoolExecutor#getActiveCount()
*/
public int getActiveCount() {
return getThreadPoolExecutor().getActiveCount();
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);
}
}
/**
* Calls <code>shutdown</code> when the BeanFactory destroys
* the task executor instance.
* @see #shutdown()
*/
public void destroy() {
shutdown();
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);
}
}
/**
* Perform a shutdown on the ThreadPoolExecutor.
* @see java.util.concurrent.ThreadPoolExecutor#shutdown()
* This task executor prefers short-lived work units.
*/
public void shutdown() {
if (logger.isInfoEnabled()) {
logger.info("Shutting down ThreadPoolExecutor" + (this.beanName != null ? " '" + this.beanName + "'" : ""));
}
if (this.waitForTasksToCompleteOnShutdown) {
this.threadPoolExecutor.shutdown();
}
else {
this.threadPoolExecutor.shutdownNow();
}
public boolean prefersShortLivedTasks() {
return true;
}
}

7
org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/package.html

@ -2,9 +2,10 @@ @@ -2,9 +2,10 @@
<body>
Scheduling convenience classes for the JDK 1.5+ Executor mechanism
in the <code>java.util.concurrent</code> package, allowing to set
up a ThreadPoolExecutor or ScheduledThreadPoolExecutor as bean in
a Spring context.
in the <code>java.util.concurrent</code> package, allowing to set up a
ThreadPoolExecutor or ScheduledThreadPoolExecutor as a bean in a Spring
context. Provides support for the native <code>java.util.concurrent</code>
interfaces as well as the Spring <code>TaskExecutor</code> mechanism.
</body>
</html>

5
org.springframework.context/src/main/java/org/springframework/scheduling/timer/TimerFactoryBean.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -103,10 +103,7 @@ public class TimerFactoryBean implements FactoryBean, BeanNameAware, Initializin @@ -103,10 +103,7 @@ public class TimerFactoryBean implements FactoryBean, BeanNameAware, Initializin
/**
* Create a new Timer instance. Called by <code>afterPropertiesSet</code>.
* Can be overridden in subclasses to provide custom Timer subclasses.
* <p>Uses the specified name as Timer thread name on JDK 1.5,
* simply falling back to a default Timer thread on JDK 1.4.
* @param name the desired name of the Timer's associated thread
* (applied on JDK 1.5 and higher; ignored on JDK 1.4)
* @param daemon whether to create a Timer that runs as daemon thread
* @return a new Timer instance
* @see #afterPropertiesSet()

33
org.springframework.context/src/main/java/org/springframework/scheduling/timer/TimerTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -17,6 +17,9 @@ @@ -17,6 +17,9 @@
package org.springframework.scheduling.timer;
import java.util.Timer;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -41,7 +44,7 @@ public class TimerTaskExecutor implements SchedulingTaskExecutor, InitializingBe @@ -41,7 +44,7 @@ public class TimerTaskExecutor implements SchedulingTaskExecutor, InitializingBe
private Timer timer;
private int delay = 0;
private long delay = 0;
private boolean timerInternal = false;
@ -76,11 +79,13 @@ public class TimerTaskExecutor implements SchedulingTaskExecutor, InitializingBe @@ -76,11 +79,13 @@ public class TimerTaskExecutor implements SchedulingTaskExecutor, InitializingBe
}
/**
* Set the delay to use for scheduling tasks passed into the
* <code>execute</code> method. Default is 0.
* Set the delay to use for scheduling tasks passed into the plain
* {@link #execute(Runnable)} method. Default is 0.
* <p>Note that calls to {@link #execute(Runnable, long)} will use the
* given timeout as delay if it is lower than the general delay.
* @param delay the delay in milliseconds before the task is to be executed
*/
public void setDelay(int delay) {
public void setDelay(long delay) {
this.delay = delay;
}
@ -117,6 +122,24 @@ public class TimerTaskExecutor implements SchedulingTaskExecutor, InitializingBe @@ -117,6 +122,24 @@ public class TimerTaskExecutor implements SchedulingTaskExecutor, InitializingBe
this.timer.schedule(new DelegatingTimerTask(task), this.delay);
}
public void execute(Runnable task, long startTimeout) {
Assert.notNull(this.timer, "Timer is required");
long actualDelay = (startTimeout < this.delay ? startTimeout : this.delay);
this.timer.schedule(new DelegatingTimerTask(task), actualDelay);
}
public Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask<Object>(task, null);
execute(future);
return future;
}
public <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask<T>(task);
execute(future);
return future;
}
/**
* This task executor prefers short-lived work units.
*/

281
org.springframework.context/src/test/java/org/springframework/scheduling/backportconcurrent/ScheduledExecutorFactoryBeanTests.java

@ -1,281 +0,0 @@ @@ -1,281 +0,0 @@
/*
* Copyright 2002-2007 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.springframework.scheduling.backportconcurrent;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import junit.framework.AssertionFailedError;
import org.easymock.MockControl;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.core.task.NoOpRunnable;
import edu.emory.mathcs.backport.java.util.concurrent.RejectedExecutionHandler;
import edu.emory.mathcs.backport.java.util.concurrent.ScheduledExecutorService;
import edu.emory.mathcs.backport.java.util.concurrent.ThreadFactory;
/**
* @author Rick Evans
* @author Juergen Hoeller
*/
public class ScheduledExecutorFactoryBeanTests {
@Test
public void testThrowsExceptionIfPoolSizeIsLessThanZero() throws Exception {
try {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setPoolSize(-1);
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new NoOpScheduledExecutorTask()
});
factory.afterPropertiesSet();
fail("Pool size less than zero");
}
catch (IllegalArgumentException expected) {
}
}
@Test
public void testShutdownNowIsPropagatedToTheExecutorOnDestroy() throws Exception {
MockControl mockScheduledExecutorService = MockControl.createNiceControl(ScheduledExecutorService.class);
final ScheduledExecutorService executor = (ScheduledExecutorService) mockScheduledExecutorService.getMock();
executor.shutdownNow();
mockScheduledExecutorService.setReturnValue(null);
mockScheduledExecutorService.replay();
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
return executor;
}
};
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new NoOpScheduledExecutorTask()
});
factory.afterPropertiesSet();
factory.destroy();
mockScheduledExecutorService.verify();
}
@Test
public void testShutdownIsPropagatedToTheExecutorOnDestroy() throws Exception {
MockControl mockScheduledExecutorService = MockControl.createNiceControl(ScheduledExecutorService.class);
final ScheduledExecutorService executor = (ScheduledExecutorService) mockScheduledExecutorService.getMock();
executor.shutdown();
mockScheduledExecutorService.setVoidCallable();
mockScheduledExecutorService.replay();
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
return executor;
}
};
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new NoOpScheduledExecutorTask()
});
factory.setWaitForTasksToCompleteOnShutdown(true);
factory.afterPropertiesSet();
factory.destroy();
mockScheduledExecutorService.verify();
}
@Test
public void testOneTimeExecutionIsSetUpAndFiresCorrectly() throws Exception {
MockControl mockRunnable = MockControl.createControl(Runnable.class);
Runnable runnable = (Runnable) mockRunnable.getMock();
runnable.run();
mockRunnable.setVoidCallable();
mockRunnable.replay();
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new ScheduledExecutorTask(runnable)
});
factory.afterPropertiesSet();
pauseToLetTaskStart(1);
factory.destroy();
mockRunnable.verify();
}
@Test
public void testFixedRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
MockControl mockRunnable = MockControl.createControl(Runnable.class);
Runnable runnable = (Runnable) mockRunnable.getMock();
runnable.run();
mockRunnable.setVoidCallable();
runnable.run();
mockRunnable.setVoidCallable();
mockRunnable.replay();
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
task.setPeriod(500);
task.setFixedRate(true);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{task});
factory.afterPropertiesSet();
pauseToLetTaskStart(2);
factory.destroy();
mockRunnable.verify();
}
@Test
public void testFixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
MockControl mockRunnable = MockControl.createControl(Runnable.class);
Runnable runnable = (Runnable) mockRunnable.getMock();
runnable.run();
mockRunnable.setThrowable(new IllegalStateException());
runnable.run();
mockRunnable.setThrowable(new IllegalStateException());
mockRunnable.replay();
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
task.setPeriod(500);
task.setFixedRate(true);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{task});
factory.setContinueScheduledExecutionAfterException(true);
factory.afterPropertiesSet();
pauseToLetTaskStart(2);
factory.destroy();
mockRunnable.verify();
}
@Ignore
@Test
public void testWithInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
MockControl mockRunnable = MockControl.createControl(Runnable.class);
Runnable runnable = (Runnable) mockRunnable.getMock();
runnable.run();
mockRunnable.setVoidCallable();
runnable.run();
mockRunnable.setVoidCallable();
mockRunnable.replay();
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
task.setPeriod(500);
task.setDelay(3000); // nice long wait...
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[] {task});
factory.afterPropertiesSet();
pauseToLetTaskStart(1);
// invoke destroy before tasks have even been scheduled...
factory.destroy();
try {
mockRunnable.verify();
fail("Mock must never have been called");
}
catch (AssertionFailedError expected) {
}
}
@Ignore
@Test
public void testWithInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
MockControl mockRunnable = MockControl.createControl(Runnable.class);
Runnable runnable = (Runnable) mockRunnable.getMock();
runnable.run();
mockRunnable.setThrowable(new IllegalStateException());
runnable.run();
mockRunnable.setThrowable(new IllegalStateException());
mockRunnable.replay();
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
task.setPeriod(500);
task.setDelay(3000); // nice long wait...
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[] {task});
factory.setContinueScheduledExecutionAfterException(true);
factory.afterPropertiesSet();
pauseToLetTaskStart(1);
// invoke destroy before tasks have even been scheduled...
factory.destroy();
try {
mockRunnable.verify();
fail("Mock must never have been called");
}
catch (AssertionFailedError expected) {
}
}
@Test
public void testSettingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
assertNotNull("Bah; the setThreadFactory(..) method must use a default ThreadFactory if a null arg is passed in.");
return super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler);
}
};
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new NoOpScheduledExecutorTask()
});
factory.setThreadFactory(null); // the null must not propagate
factory.afterPropertiesSet();
factory.destroy();
}
@Test
public void testSettingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
assertNotNull("Bah; the setRejectedExecutionHandler(..) method must use a default RejectedExecutionHandler if a null arg is passed in.");
return super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler);
}
};
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new NoOpScheduledExecutorTask()
});
factory.setRejectedExecutionHandler(null); // the null must not propagate
factory.afterPropertiesSet();
factory.destroy();
}
@Test
public void testObjectTypeReportsCorrectType() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
assertEquals(ScheduledExecutorService.class, factory.getObjectType());
}
private static void pauseToLetTaskStart(int seconds) {
try {
Thread.sleep(seconds * 1000);
}
catch (InterruptedException ignored) {
}
}
private static class NoOpScheduledExecutorTask extends ScheduledExecutorTask {
public NoOpScheduledExecutorTask() {
super(new NoOpRunnable());
}
}
}

43
org.springframework.core/src/main/java/org/springframework/core/task/AsyncTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@ -16,19 +16,28 @@ @@ -16,19 +16,28 @@
package org.springframework.core.task;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
/**
* Extended interface for asynchronous {@link TaskExecutor} implementations,
* offering an overloaded {@link #execute(Runnable, long)} variant with
* start timeout parameter.
* offering an overloaded {@link #execute(Runnable, long)} variant with a start
* timeout parameter as well support for {@link java.util.concurrent.Callable}.
*
* <p>Note: The {@link java.util.concurrent.Executors} class includes a set of
* methods that can convert some other common closure-like objects, for example,
* {@link java.security.PrivilegedAction} to {@link Callable} before executing them.
*
* <p>Implementing this interface also indicates that the {@link #execute(Runnable)}
* method will not execute its Runnable in the caller's thread but rather
* asynchronously in some other thread (at least usually).
* asynchronously in some other thread.
*
* @author Juergen Hoeller
* @since 2.0.3
* @see SimpleAsyncTaskExecutor
* @see org.springframework.scheduling.SchedulingTaskExecutor
* @see java.util.concurrent.Callable
* @see java.util.concurrent.Executors
*/
public interface AsyncTaskExecutor extends TaskExecutor {
@ -42,14 +51,32 @@ public interface AsyncTaskExecutor extends TaskExecutor { @@ -42,14 +51,32 @@ public interface AsyncTaskExecutor extends TaskExecutor {
/**
* Execute the given <code>task</code>.
* @param task the <code>Runnable</code> to execute (never <code>null</code>)
* @param startTimeout the time duration within which the task is supposed to start.
* This is intended as a hint to the executor, allowing for preferred handling
* of immediate tasks. Typical values are {@link #TIMEOUT_IMMEDIATE} or
* {@link #TIMEOUT_INDEFINITE} (the default as used by {@link #execute(Runnable)}).
* @param startTimeout the time duration (milliseconds) within which the task is
* supposed to start. This is intended as a hint to the executor, allowing for
* preferred handling of immediate tasks. Typical values are {@link #TIMEOUT_IMMEDIATE}
* or {@link #TIMEOUT_INDEFINITE} (the default as used by {@link #execute(Runnable)}).
* @throws TaskTimeoutException in case of the task being rejected because
* of the timeout (i.e. it cannot be started in time)
* @throws TaskRejectedException if the given task was not accepted
*/
void execute(Runnable task, long startTimeout);
/**
* Submit a Runnable task for execution, receiving a Future representing that task.
* The Future will return a <code>null</code> result upon completion.
* @param task the <code>Runnable</code> to execute (never <code>null</code>)
* @return a Future representing pending completion of the task
* @throws TaskRejectedException if the given task was not accepted
*/
Future<?> submit(Runnable task);
/**
* Submit a Callable task for execution, receiving a Future representing that task.
* The Future will return the Callable's result upon completion.
* @param task the <code>Callable</code> to execute (never <code>null</code>)
* @return a Future representing pending completion of the task
* @throws TaskRejectedException if the given task was not accepted
*/
<T> Future<T> submit(Callable<T> task);
}

59
org.springframework.core/src/main/java/org/springframework/core/task/SimpleAsyncTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -17,6 +17,10 @@ @@ -17,6 +17,10 @@
package org.springframework.core.task;
import java.io.Serializable;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadFactory;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrencyThrottleSupport;
@ -54,11 +58,11 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement @@ -54,11 +58,11 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement
public static final int NO_CONCURRENCY = ConcurrencyThrottleSupport.NO_CONCURRENCY;
/**
* Internal concurrency throttle used by this executor.
*/
/** Internal concurrency throttle used by this executor */
private final ConcurrencyThrottleAdapter concurrencyThrottle = new ConcurrencyThrottleAdapter();
private ThreadFactory threadFactory;
/**
* Create a new SimpleAsyncTaskExecutor with default thread name prefix.
@ -75,6 +79,33 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement @@ -75,6 +79,33 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement
super(threadNamePrefix);
}
/**
* Create a new SimpleAsyncTaskExecutor with the given external thread factory.
* @param threadFactory the factory to use for creating new Threads
*/
public SimpleAsyncTaskExecutor(ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
}
/**
* Specify an external factory to use for creating new Threads,
* instead of relying on the local properties of this executor.
* <p>You may specify an inner ThreadFactory bean or also a ThreadFactory reference
* obtained from JNDI (on a Java EE 6 server) or some other lookup mechanism.
* @see #setThreadNamePrefix
* @see #setThreadPriority
*/
public void setThreadFactory(ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
}
/**
* Return the external factory to use for creating new Threads, if any.
*/
public final ThreadFactory getThreadFactory() {
return this.threadFactory;
}
/**
* Set the maximum number of parallel accesses allowed.
@ -93,7 +124,7 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement @@ -93,7 +124,7 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement
/**
* Return the maximum number of parallel accesses allowed.
*/
public int getConcurrencyLimit() {
public final int getConcurrencyLimit() {
return this.concurrencyThrottle.getConcurrencyLimit();
}
@ -103,7 +134,7 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement @@ -103,7 +134,7 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement
* @see #getConcurrencyLimit()
* @see #setConcurrencyLimit
*/
public boolean isThrottleActive() {
public final boolean isThrottleActive() {
return this.concurrencyThrottle.isThrottleActive();
}
@ -137,15 +168,29 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement @@ -137,15 +168,29 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implement
}
}
public Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask<Object>(task, null);
execute(future, TIMEOUT_INDEFINITE);
return future;
}
public <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask<T>(task);
execute(future, TIMEOUT_INDEFINITE);
return future;
}
/**
* Template method for the actual execution of a task.
* <p>The default implementation creates a new Thread and starts it.
* @param task the Runnable to execute
* @see #setThreadFactory
* @see #createThread
* @see java.lang.Thread#start()
*/
protected void doExecute(Runnable task) {
createThread(task).start();
Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
thread.start();
}

12
org.springframework.core/src/main/java/org/springframework/core/task/support/ConcurrentExecutorAdapter.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -22,14 +22,18 @@ import org.springframework.core.task.TaskExecutor; @@ -22,14 +22,18 @@ import org.springframework.core.task.TaskExecutor;
import org.springframework.util.Assert;
/**
* Adapter that exposes the {@link java.util.concurrent.Executor}
* interface for any Spring {@link org.springframework.core.task.TaskExecutor}.
* Adapter that exposes the {@link java.util.concurrent.Executor} interface
* for any Spring {@link org.springframework.core.task.TaskExecutor}.
*
* <p>This is less useful as of Spring 3.0, since TaskExecutor itself
* extends the Executor interface. The adapter is only relevant for
* <em>hiding</em> the TaskExecutor nature of a given object now,
* solely exposing the standard Executor interface to a client.
*
* @author Juergen Hoeller
* @since 2.5
* @see java.util.concurrent.Executor
* @see org.springframework.core.task.TaskExecutor
* @deprecated as of Spring 3.0 since TaskExecutor itself implements the Executor interface now
*/
public class ConcurrentExecutorAdapter implements Executor {

87
org.springframework.core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java

@ -0,0 +1,87 @@ @@ -0,0 +1,87 @@
/*
* Copyright 2002-2009 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.springframework.core.task.support;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.TimeUnit;
import org.springframework.core.task.TaskExecutor;
import org.springframework.util.Assert;
/**
* Adapter that takes a Spring {@link org.springframework.core.task.TaskExecutor})
* and exposes a full <code>java.util.concurrent.ExecutorService</code> for it.
*
* <p>This is primarily for adapting to client components that communicate via the
* <code>java.util.concurrent.ExecutorService</code> API. It can also be used as
* common ground between a local Spring <code>TaskExecutor</code> backend and a
* JNDI-located <code>ManagedExecutorService</code> in a Java EE 6 environment.
*
* <p><b>NOTE:</b> This ExecutorService adapter does <em>not</em> support the
* lifecycle methods in the <code>java.util.concurrent.ExecutorService</code> API
* ("shutdown()" etc), similar to a server-wide <code>ManagedExecutorService</code>
* in a Java EE 6 environment. The lifecycle is always up to the backend pool,
* with this adapter acting as an access-only proxy for that target pool.
*
* @author Juergen Hoeller
* @since 3.0
* @see java.util.concurrent.ExecutorService
*/
public class ExecutorServiceAdapter extends AbstractExecutorService {
private final TaskExecutor taskExecutor;
/**
* Create a new ExecutorServiceAdapter, using the given target executor.
* @param concurrentExecutor the target executor to delegate to
*/
public ExecutorServiceAdapter(TaskExecutor taskExecutor) {
Assert.notNull(taskExecutor, "TaskExecutor must not be null");
this.taskExecutor = taskExecutor;
}
public void execute(Runnable task) {
this.taskExecutor.execute(task);
}
public void shutdown() {
throw new IllegalStateException(
"Manual shutdown not supported - ExecutorServiceAdapter is dependent on an external lifecycle");
}
public List<Runnable> shutdownNow() {
throw new IllegalStateException(
"Manual shutdown not supported - ExecutorServiceAdapter is dependent on an external lifecycle");
}
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
throw new IllegalStateException(
"Manual shutdown not supported - ExecutorServiceAdapter is dependent on an external lifecycle");
}
public boolean isShutdown() {
return false;
}
public boolean isTerminated() {
return false;
}
}

110
org.springframework.core/src/main/java/org/springframework/core/task/support/TaskExecutorAdapter.java

@ -0,0 +1,110 @@ @@ -0,0 +1,110 @@
/*
* Copyright 2002-2009 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.springframework.core.task.support;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RejectedExecutionException;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.util.Assert;
/**
* Adapter that takes a JDK 1.5 <code>java.util.concurrent.Executor</code> and
* exposes a Spring {@link org.springframework.core.task.TaskExecutor} for it.
* Also detects an extended <code>java.util.concurrent.ExecutorService</code>, adapting
* the {@link org.springframework.core.task.AsyncTaskExecutor} interface accordingly.
*
* @author Juergen Hoeller
* @since 3.0
* @see java.util.concurrent.Executor
* @see java.util.concurrent.ExecutorService
* @see java.util.concurrent.Executors
*/
public class TaskExecutorAdapter implements AsyncTaskExecutor {
private Executor concurrentExecutor;
/**
* Create a new TaskExecutorAdapter,
* using the given JDK 1.5 concurrent executor.
* @param concurrentExecutor the JDK 1.5 concurrent executor to delegate to
*/
public TaskExecutorAdapter(Executor concurrentExecutor) {
Assert.notNull(concurrentExecutor, "Executor must not be null");
this.concurrentExecutor = concurrentExecutor;
}
/**
* Delegates to the specified JDK 1.5 concurrent executor.
* @see java.util.concurrent.Executor#execute(Runnable)
*/
public void execute(Runnable task) {
try {
this.concurrentExecutor.execute(task);
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException(
"Executor [" + this.concurrentExecutor + "] did not accept task: " + task, ex);
}
}
public void execute(Runnable task, long startTimeout) {
execute(task);
}
public Future<?> submit(Runnable task) {
try {
if (this.concurrentExecutor instanceof ExecutorService) {
return ((ExecutorService) this.concurrentExecutor).submit(task);
}
else {
FutureTask<Object> future = new FutureTask<Object>(task, null);
this.concurrentExecutor.execute(future);
return future;
}
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException(
"Executor [" + this.concurrentExecutor + "] did not accept task: " + task, ex);
}
}
public <T> Future<T> submit(Callable<T> task) {
try {
if (this.concurrentExecutor instanceof ExecutorService) {
return ((ExecutorService) this.concurrentExecutor).submit(task);
}
else {
FutureTask<T> future = new FutureTask<T>(task);
this.concurrentExecutor.execute(future);
return future;
}
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException(
"Executor [" + this.concurrentExecutor + "] did not accept task: " + task, ex);
}
}
}

2
org.springframework.core/src/main/java/org/springframework/core/task/support/package.html

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<body>
Support classes for Spring's TaskExecutor abstraction.
Includes an adapter for the JDK 1.5 Executor interface.
Includes an adapter for the standard ExecutorService interface.
</body>
</html>

15
org.springframework.core/src/main/java/org/springframework/util/CustomizableThreadCreator.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
package org.springframework.util;
import java.io.Serializable;
/**
* Simple customizable helper class for creating threads. Provides various
* bean properties, such as thread name prefix, thread priority, etc.
@ -27,7 +29,7 @@ package org.springframework.util; @@ -27,7 +29,7 @@ package org.springframework.util;
* @since 2.0.3
* @see org.springframework.scheduling.concurrent.CustomizableThreadFactory
*/
public class CustomizableThreadCreator {
public class CustomizableThreadCreator implements Serializable {
private String threadNamePrefix;
@ -39,7 +41,7 @@ public class CustomizableThreadCreator { @@ -39,7 +41,7 @@ public class CustomizableThreadCreator {
private int threadCount = 0;
private final Object threadCountMonitor = new Object();
private final Object threadCountMonitor = new SerializableMonitor();
/**
@ -174,4 +176,11 @@ public class CustomizableThreadCreator { @@ -174,4 +176,11 @@ public class CustomizableThreadCreator {
return ClassUtils.getShortName(getClass()) + "-";
}
/**
* Empty class used for a serializable monitor object.
*/
private static class SerializableMonitor implements Serializable {
}
}

15
org.springframework.core/src/test/java/org/springframework/core/task/SimpleAsyncTaskExecutorTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@ -16,9 +16,10 @@ @@ -16,9 +16,10 @@
package org.springframework.core.task;
import java.util.concurrent.ThreadFactory;
import junit.framework.TestCase;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrencyThrottleSupport;
/**
@ -52,12 +53,16 @@ public final class SimpleAsyncTaskExecutorTests extends TestCase { @@ -52,12 +53,16 @@ public final class SimpleAsyncTaskExecutorTests extends TestCase {
assertTrue(task.getThreadName().startsWith(customPrefix));
}
public void testThreadNameRevertsToDefaultIfSetToNull() throws Exception {
public void testThreadFactoryOverridesDefaults() throws Exception {
final Object monitor = new Object();
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(null);
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(r, "test");
}
});
ThreadNameHarvester task = new ThreadNameHarvester(monitor);
executeAndWait(executor, task, monitor);
assertTrue(task.getThreadName().startsWith(ClassUtils.getShortName(SimpleAsyncTaskExecutor.class) + "-"));
assertTrue(task.getThreadName().equals("test"));
}
public void testThrowsExceptionWhenSuppliedWithNullRunnable() throws Exception {

6
org.springframework.transaction/src/main/java/org/springframework/jca/work/SimpleTaskWorkManager.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@ -64,7 +64,7 @@ public class SimpleTaskWorkManager implements WorkManager { @@ -64,7 +64,7 @@ public class SimpleTaskWorkManager implements WorkManager {
private TaskExecutor syncTaskExecutor = new SyncTaskExecutor();
private TaskExecutor asyncTaskExecutor = new SimpleAsyncTaskExecutor();
private AsyncTaskExecutor asyncTaskExecutor = new SimpleAsyncTaskExecutor();
/**
@ -83,7 +83,7 @@ public class SimpleTaskWorkManager implements WorkManager { @@ -83,7 +83,7 @@ public class SimpleTaskWorkManager implements WorkManager {
* {@link org.springframework.core.task.AsyncTaskExecutor} implementation.
* Default is a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}.
*/
public void setAsyncTaskExecutor(TaskExecutor asyncTaskExecutor) {
public void setAsyncTaskExecutor(AsyncTaskExecutor asyncTaskExecutor) {
this.asyncTaskExecutor = asyncTaskExecutor;
}

19
org.springframework.transaction/src/main/java/org/springframework/jca/work/WorkManagerTaskExecutor.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@ -16,6 +16,9 @@ @@ -16,6 +16,9 @@
package org.springframework.jca.work;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import javax.naming.NamingException;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.work.ExecutionContext;
@ -161,7 +164,7 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport @@ -161,7 +164,7 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
public void afterPropertiesSet() throws NamingException {
if (this.workManager == null) {
if (this.workManagerName != null) {
this.workManager = (WorkManager) lookup(this.workManagerName, WorkManager.class);
this.workManager = lookup(this.workManagerName, WorkManager.class);
}
else {
this.workManager = getDefaultWorkManager();
@ -230,6 +233,18 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport @@ -230,6 +233,18 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
}
}
public Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask<Object>(task, null);
execute(future, TIMEOUT_INDEFINITE);
return future;
}
public <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask<T>(task);
execute(future, TIMEOUT_INDEFINITE);
return future;
}
/**
* This task executor prefers short-lived work units.
*/

Loading…
Cancel
Save