org.apache.activemq.thread.TaskRunnerFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of activemq-client Show documentation
Show all versions of activemq-client Show documentation
The ActiveMQ Client implementation
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.activemq.thread;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
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 java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.activemq.util.ThreadPoolUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Manages the thread pool for long running tasks. Long running tasks are not
* always active but when they are active, they may need a few iterations of
* processing for them to become idle. The manager ensures that each task is
* processes but that no one task overtakes the system. This is somewhat like
* cooperative multitasking.
*
* @org.apache.xbean.XBean
*/
public class TaskRunnerFactory implements Executor {
private static final Logger LOG = LoggerFactory.getLogger(TaskRunnerFactory.class);
private final AtomicReference executorRef = new AtomicReference<>();
private int maxIterationsPerRun;
private String name;
private int priority;
private boolean daemon;
private final AtomicLong id = new AtomicLong(0);
private boolean dedicatedTaskRunner;
private long shutdownAwaitTermination = 30000;
private final AtomicBoolean initDone = new AtomicBoolean(false);
private int maxThreadPoolSize = getDefaultMaximumPoolSize();
private RejectedExecutionHandler rejectedTaskHandler = null;
private ClassLoader threadClassLoader;
public TaskRunnerFactory() {
this("ActiveMQ Task");
}
public TaskRunnerFactory(String name) {
this(name, Thread.NORM_PRIORITY, true, 1000);
}
private TaskRunnerFactory(String name, int priority, boolean daemon, int maxIterationsPerRun) {
this(name, priority, daemon, maxIterationsPerRun, false);
}
public TaskRunnerFactory(String name, int priority, boolean daemon, int maxIterationsPerRun, boolean dedicatedTaskRunner) {
this(name, priority, daemon, maxIterationsPerRun, dedicatedTaskRunner, getDefaultMaximumPoolSize());
}
public TaskRunnerFactory(String name, int priority, boolean daemon, int maxIterationsPerRun, boolean dedicatedTaskRunner, int maxThreadPoolSize) {
this.name = name;
this.priority = priority;
this.daemon = daemon;
this.maxIterationsPerRun = maxIterationsPerRun;
this.dedicatedTaskRunner = dedicatedTaskRunner;
this.maxThreadPoolSize = maxThreadPoolSize;
}
public void init() {
if (!initDone.get()) {
// If your OS/JVM combination has a good thread model, you may want to
// avoid using a thread pool to run tasks and use a DedicatedTaskRunner instead.
//AMQ-6602 - lock instead of using compareAndSet to prevent threads from seeing a null value
//for executorRef inside createTaskRunner() on contention and creating a DedicatedTaskRunner
synchronized(this) {
//need to recheck if initDone is true under the lock
if (!initDone.get()) {
if (dedicatedTaskRunner || "true".equalsIgnoreCase(System.getProperty("org.apache.activemq.UseDedicatedTaskRunner"))) {
executorRef.set(null);
} else {
executorRef.compareAndSet(null, createDefaultExecutor());
}
LOG.debug("Initialized TaskRunnerFactory[{}] using ExecutorService: {}", name, executorRef.get());
initDone.set(true);
}
}
}
}
/**
* Performs a shutdown only, by which the thread pool is shutdown by not graceful nor aggressively.
*
* @see ThreadPoolUtils#shutdown(java.util.concurrent.ExecutorService)
*/
public void shutdown() {
ExecutorService executor = executorRef.get();
if (executor != null) {
ThreadPoolUtils.shutdown(executor);
}
clearExecutor();
}
/**
* Performs a shutdown now (aggressively) on the thread pool.
*
* @see ThreadPoolUtils#shutdownNow(java.util.concurrent.ExecutorService)
*/
public void shutdownNow() {
ExecutorService executor = executorRef.get();
if (executor != null) {
ThreadPoolUtils.shutdownNow(executor);
}
clearExecutor();
}
/**
* Performs a graceful shutdown.
*
* @see ThreadPoolUtils#shutdownGraceful(java.util.concurrent.ExecutorService)
*/
public void shutdownGraceful() {
ExecutorService executor = executorRef.get();
if (executor != null) {
ThreadPoolUtils.shutdownGraceful(executor, shutdownAwaitTermination);
}
clearExecutor();
}
private void clearExecutor() {
//clear under a lock to prevent threads from seeing initDone == true
//but then getting null from executorRef
synchronized(this) {
executorRef.set(null);
initDone.set(false);
}
}
public TaskRunner createTaskRunner(Task task, String name) {
init();
ExecutorService executor = executorRef.get();
if (executor != null) {
return new PooledTaskRunner(executor, task, maxIterationsPerRun);
} else {
return new DedicatedTaskRunner(task, name, priority, daemon);
}
}
@Override
public void execute(Runnable runnable) {
execute(runnable, name);
}
public void execute(Runnable runnable, String name) {
init();
LOG.trace("Execute[{}] runnable: {}", name, runnable);
ExecutorService executor = executorRef.get();
if (executor != null) {
executor.execute(runnable);
} else {
doExecuteNewThread(runnable, name);
}
}
private void doExecuteNewThread(Runnable runnable, String name) {
String threadName = name + "-" + id.incrementAndGet();
Thread thread = new Thread(runnable, threadName);
thread.setDaemon(daemon);
LOG.trace("Created and running thread[{}]: {}", threadName, thread);
thread.start();
}
protected ExecutorService createDefaultExecutor() {
ThreadPoolExecutor rc = new ThreadPoolExecutor(getDefaultCorePoolSize(), getMaxThreadPoolSize(), getDefaultKeepAliveTime(), TimeUnit.SECONDS, new SynchronousQueue(), new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
String threadName = name + "-" + id.incrementAndGet();
Thread thread = new Thread(runnable, threadName);
thread.setDaemon(daemon);
thread.setPriority(priority);
if (threadClassLoader != null) {
thread.setContextClassLoader(threadClassLoader);
}
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(final Thread t, final Throwable e) {
LOG.error("Error in thread '{}'", t.getName(), e);
}
});
LOG.trace("Created thread[{}]: {}", threadName, thread);
return thread;
}
});
if (rejectedTaskHandler != null) {
rc.setRejectedExecutionHandler(rejectedTaskHandler);
} else {
rc.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
}
return rc;
}
public ExecutorService getExecutor() {
return executorRef.get();
}
public void setExecutor(ExecutorService executor) {
this.executorRef.set(executor);
}
public int getMaxIterationsPerRun() {
return maxIterationsPerRun;
}
public void setMaxIterationsPerRun(int maxIterationsPerRun) {
this.maxIterationsPerRun = maxIterationsPerRun;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public boolean isDaemon() {
return daemon;
}
public void setDaemon(boolean daemon) {
this.daemon = daemon;
}
public boolean isDedicatedTaskRunner() {
return dedicatedTaskRunner;
}
public void setDedicatedTaskRunner(boolean dedicatedTaskRunner) {
this.dedicatedTaskRunner = dedicatedTaskRunner;
}
public int getMaxThreadPoolSize() {
return maxThreadPoolSize;
}
public void setMaxThreadPoolSize(int maxThreadPoolSize) {
this.maxThreadPoolSize = maxThreadPoolSize;
}
public void setThreadClassLoader(ClassLoader threadClassLoader) {
this.threadClassLoader = threadClassLoader;
}
public RejectedExecutionHandler getRejectedTaskHandler() {
return rejectedTaskHandler;
}
public void setRejectedTaskHandler(RejectedExecutionHandler rejectedTaskHandler) {
this.rejectedTaskHandler = rejectedTaskHandler;
}
public long getShutdownAwaitTermination() {
return shutdownAwaitTermination;
}
public void setShutdownAwaitTermination(long shutdownAwaitTermination) {
this.shutdownAwaitTermination = shutdownAwaitTermination;
}
private static int getDefaultCorePoolSize() {
return Integer.getInteger("org.apache.activemq.thread.TaskRunnerFactory.corePoolSize", 0);
}
private static int getDefaultMaximumPoolSize() {
return Integer.getInteger("org.apache.activemq.thread.TaskRunnerFactory.maximumPoolSize", Integer.MAX_VALUE);
}
private static int getDefaultKeepAliveTime() {
return Integer.getInteger("org.apache.activemq.thread.TaskRunnerFactory.keepAliveTime", 30);
}
}