org.eclipse.jetty.util.thread.ExecutorThreadPool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util.thread;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.jetty.util.ProcessorUtils;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.component.DumpableCollection;
/**
* A {@link org.eclipse.jetty.util.thread.ThreadPool.SizedThreadPool} wrapper around {@link ThreadPoolExecutor}.
*
* @deprecated The Eclipse Jetty and Apache Felix Http Jetty packages are no longer supported.
*/
@ManagedObject("A thread pool")
@Deprecated(since = "2021-05-27")
public class ExecutorThreadPool extends ContainerLifeCycle implements ThreadPool.SizedThreadPool, TryExecutor {
private final ThreadPoolExecutor _executor;
private final ThreadPoolBudget _budget;
private final ThreadGroup _group;
private String _name = "etp" + hashCode();
private int _minThreads;
private int _reservedThreads = -1;
private TryExecutor _tryExecutor = TryExecutor.NO_TRY;
private int _priority = Thread.NORM_PRIORITY;
private boolean _daemon;
private boolean _detailedDump;
public ExecutorThreadPool() {
this(200, 8);
}
public ExecutorThreadPool(int maxThreads) {
this(maxThreads, Math.min(8, maxThreads));
}
public ExecutorThreadPool(int maxThreads, int minThreads) {
this(maxThreads, minThreads, new LinkedBlockingQueue<>());
}
public ExecutorThreadPool(int maxThreads, int minThreads, BlockingQueue queue) {
this(new ThreadPoolExecutor(maxThreads, maxThreads, 60, TimeUnit.SECONDS, queue), minThreads, -1, null);
}
public ExecutorThreadPool(ThreadPoolExecutor executor) {
this(executor, -1);
}
public ExecutorThreadPool(ThreadPoolExecutor executor, int reservedThreads) {
this(executor, reservedThreads, null);
}
public ExecutorThreadPool(ThreadPoolExecutor executor, int reservedThreads, ThreadGroup group) {
this(executor, Math.min(ProcessorUtils.availableProcessors(), executor.getCorePoolSize()), reservedThreads, group);
}
private ExecutorThreadPool(ThreadPoolExecutor executor, int minThreads, int reservedThreads, ThreadGroup group) {
int maxThreads = executor.getMaximumPoolSize();
if (maxThreads < minThreads) {
executor.shutdownNow();
throw new IllegalArgumentException("max threads (" + maxThreads + ") cannot be less than min threads (" + minThreads + ")");
}
_executor = executor;
_executor.setThreadFactory(this::newThread);
_group = group;
_minThreads = minThreads;
_reservedThreads = reservedThreads;
_budget = new ThreadPoolBudget(this);
}
/**
* @return the name of the this thread pool
*/
@ManagedAttribute("name of this thread pool")
public String getName() {
return _name;
}
/**
* @param name the name of this thread pool, used to name threads
*/
public void setName(String name) {
if (isRunning())
throw new IllegalStateException(getState());
_name = name;
}
@Override
@ManagedAttribute("minimum number of threads in the pool")
public int getMinThreads() {
return _minThreads;
}
@Override
public void setMinThreads(int threads) {
_minThreads = threads;
}
@Override
@ManagedAttribute("maximum number of threads in the pool")
public int getMaxThreads() {
return _executor.getMaximumPoolSize();
}
@Override
public void setMaxThreads(int threads) {
if (_budget != null)
_budget.check(threads);
_executor.setCorePoolSize(threads);
_executor.setMaximumPoolSize(threads);
}
/**
* @return the maximum thread idle time in ms.
* @see #setIdleTimeout(int)
*/
@ManagedAttribute("maximum time a thread may be idle in ms")
public int getIdleTimeout() {
return (int) _executor.getKeepAliveTime(TimeUnit.MILLISECONDS);
}
/**
* Sets the maximum thread idle time in ms.
* Threads that are idle for longer than this
* period may be stopped.
*
* @param idleTimeout the maximum thread idle time in ms.
* @see #getIdleTimeout()
*/
public void setIdleTimeout(int idleTimeout) {
_executor.setKeepAliveTime(idleTimeout, TimeUnit.MILLISECONDS);
}
/**
* @return number of reserved threads or -1 to indicate that the number is heuristically determined
* @see #setReservedThreads(int)
*/
@ManagedAttribute("the number of reserved threads in the pool")
public int getReservedThreads() {
if (isStarted())
return getBean(ReservedThreadExecutor.class).getCapacity();
return _reservedThreads;
}
/**
* Sets the number of reserved threads.
*
* @param reservedThreads number of reserved threads or -1 to determine the number heuristically
* @see #getReservedThreads()
*/
public void setReservedThreads(int reservedThreads) {
if (isRunning())
throw new IllegalStateException(getState());
_reservedThreads = reservedThreads;
}
public void setThreadsPriority(int priority) {
_priority = priority;
}
public int getThreadsPriority() {
return _priority;
}
/**
* @return whether this thread pool uses daemon threads
* @see #setDaemon(boolean)
*/
@ManagedAttribute("whether this thread pool uses daemon threads")
public boolean isDaemon() {
return _daemon;
}
/**
* @param daemon whether this thread pool uses daemon threads
* @see Thread#setDaemon(boolean)
*/
public void setDaemon(boolean daemon) {
_daemon = daemon;
}
@ManagedAttribute("reports additional details in the dump")
public boolean isDetailedDump() {
return _detailedDump;
}
public void setDetailedDump(boolean detailedDump) {
_detailedDump = detailedDump;
}
@Override
@ManagedAttribute("number of threads in the pool")
public int getThreads() {
return _executor.getPoolSize();
}
@Override
@ManagedAttribute("number of idle threads in the pool")
public int getIdleThreads() {
return _executor.getPoolSize() - _executor.getActiveCount();
}
@Override
public void execute(Runnable command) {
_executor.execute(command);
}
@Override
public boolean tryExecute(Runnable task) {
TryExecutor tryExecutor = _tryExecutor;
return tryExecutor != null && tryExecutor.tryExecute(task);
}
@Override
@ManagedAttribute(value = "thread pool is low on threads", readonly = true)
public boolean isLowOnThreads() {
return getThreads() == getMaxThreads() && _executor.getQueue().size() >= getIdleThreads();
}
@Override
protected void doStart() throws Exception {
if (_executor.isShutdown())
throw new IllegalStateException("This thread pool is not restartable");
for (int i = 0; i < _minThreads; ++i) {
_executor.prestartCoreThread();
}
_tryExecutor = new ReservedThreadExecutor(this, _reservedThreads);
addBean(_tryExecutor);
super.doStart();
}
@Override
protected void doStop() throws Exception {
super.doStop();
removeBean(_tryExecutor);
_tryExecutor = TryExecutor.NO_TRY;
_executor.shutdownNow();
_budget.reset();
}
@Override
public void join() throws InterruptedException {
_executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
}
@Override
public ThreadPoolBudget getThreadPoolBudget() {
return _budget;
}
protected Thread newThread(Runnable job) {
Thread thread = new Thread(_group, job);
thread.setDaemon(isDaemon());
thread.setPriority(getThreadsPriority());
thread.setName(getName() + "-" + thread.getId());
return thread;
}
@Override
public void dump(Appendable out, String indent) throws IOException {
String prefix = getName() + "-";
List threads = Thread.getAllStackTraces().entrySet().stream().filter(entry -> entry.getKey().getName().startsWith(prefix)).map(entry -> {
Thread thread = entry.getKey();
StackTraceElement[] frames = entry.getValue();
String knownMethod = null;
for (StackTraceElement frame : frames) {
if ("getTask".equals(frame.getMethodName()) && frame.getClassName().endsWith("ThreadPoolExecutor")) {
knownMethod = "IDLE ";
break;
} else if ("reservedWait".equals(frame.getMethodName()) && frame.getClassName().endsWith("ReservedThread")) {
knownMethod = "RESERVED ";
break;
} else if ("select".equals(frame.getMethodName()) && frame.getClassName().endsWith("SelectorProducer")) {
knownMethod = "SELECTING ";
break;
} else if ("accept".equals(frame.getMethodName()) && frame.getClassName().contains("ServerConnector")) {
knownMethod = "ACCEPTING ";
break;
}
}
String known = knownMethod == null ? "" : knownMethod;
return new Dumpable() {
@Override
public void dump(Appendable out, String indent) throws IOException {
StringBuilder b = new StringBuilder();
b.append(thread.getId()).append(" ").append(thread.getName()).append(" p=").append(thread.getPriority()).append(" ").append(known).append(thread.getState().toString());
if (isDetailedDump()) {
if (known.isEmpty())
Dumpable.dumpObjects(out, indent, b.toString(), (Object[]) frames);
else
Dumpable.dumpObject(out, b.toString());
} else {
b.append(" @ ").append(frames.length > 0 ? String.valueOf(frames[0]) : "");
Dumpable.dumpObject(out, b.toString());
}
}
@Override
public String dump() {
return null;
}
};
}).collect(Collectors.toList());
List jobs = Collections.emptyList();
if (isDetailedDump())
jobs = new ArrayList<>(_executor.getQueue());
dumpObjects(out, indent, threads, new DumpableCollection("jobs", jobs));
}
@Override
public String toString() {
return String.format("%s[%s]@%x{%s,%d<=%d<=%d,i=%d,q=%d,%s}", getClass().getSimpleName(), getName(), hashCode(), getState(), getMinThreads(), getThreads(), getMaxThreads(), getIdleThreads(), _executor.getQueue().size(), _tryExecutor);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy