org.glassfish.tyrus.client.ThreadPoolConfig Maven / Gradle / Ivy
/*
* Copyright (c) 2014, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.tyrus.client;
import java.util.Queue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* Client thread pool configuration, which might be used to customize client thread pool.
*
* One can get a default ThreadPoolConfig
using {@link ThreadPoolConfig#defaultConfig()}
* and customize it according to the application specific requirements.
*
* A ThreadPoolConfig
object might be customized in a "Builder"-like fashion:
*
* ThreadPoolConfig.defaultConfig()
* .setPoolName("App1Pool")
* .setCorePoolSize(5)
* .setMaxPoolSize(10);
*
*
* @author Oleksiy Stashok
* @author gustav trede
*/
public final class ThreadPoolConfig {
private static final int DEFAULT_CORE_POOL_SIZE = 1;
private static final int DEFAULT_MAX_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 20);
private static final int DEFAULT_MAX_QUEUE_SIZE = -1;
private static final int DEFAULT_IDLE_THREAD_KEEP_ALIVE_TIMEOUT = 10;
private static final ThreadPoolConfig DEFAULT = new ThreadPoolConfig(
"Tyrus-client", DEFAULT_CORE_POOL_SIZE,
DEFAULT_MAX_POOL_SIZE,
null, DEFAULT_MAX_QUEUE_SIZE,
DEFAULT_IDLE_THREAD_KEEP_ALIVE_TIMEOUT,
TimeUnit.SECONDS,
null, Thread.NORM_PRIORITY, true, null);
/**
* Create new client thread pool configuration instance. The returned ThreadPoolConfig
instance will be
* pre-configured with a default values.
*
* @return client thread pool configuration instance.
*/
public static ThreadPoolConfig defaultConfig() {
return DEFAULT.copy();
}
private String poolName;
private int corePoolSize;
private int maxPoolSize;
private Queue queue;
private int queueLimit = -1;
private long keepAliveTimeMillis;
private ThreadFactory threadFactory;
private int priority = Thread.MAX_PRIORITY;
private boolean isDaemon;
private ClassLoader initialClassLoader;
private ThreadPoolConfig(String poolName, int corePoolSize, int maxPoolSize, Queue queue, int queueLimit,
long keepAliveTime, TimeUnit timeUnit, ThreadFactory threadFactory, int priority,
boolean isDaemon, ClassLoader initialClassLoader) {
this.poolName = poolName;
this.corePoolSize = corePoolSize;
this.maxPoolSize = maxPoolSize;
this.queue = queue;
this.queueLimit = queueLimit;
if (keepAliveTime > 0) {
this.keepAliveTimeMillis =
TimeUnit.MILLISECONDS.convert(keepAliveTime, timeUnit);
} else {
keepAliveTimeMillis = keepAliveTime;
}
this.threadFactory = threadFactory;
this.priority = priority;
this.isDaemon = isDaemon;
this.initialClassLoader = initialClassLoader;
}
private ThreadPoolConfig(ThreadPoolConfig cfg) {
this.queue = cfg.queue;
this.threadFactory = cfg.threadFactory;
this.poolName = cfg.poolName;
this.priority = cfg.priority;
this.isDaemon = cfg.isDaemon;
this.maxPoolSize = cfg.maxPoolSize;
this.queueLimit = cfg.queueLimit;
this.corePoolSize = cfg.corePoolSize;
this.keepAliveTimeMillis = cfg.keepAliveTimeMillis;
this.initialClassLoader = cfg.initialClassLoader;
}
/**
* Return a copy of this thread pool config.
*
* @return a copy of this thread pool config.
*/
public ThreadPoolConfig copy() {
return new ThreadPoolConfig(this);
}
/**
* Return a queue that will be used to temporarily store tasks when all threads in the thread pool are busy.
*
* @return queue that will be used to temporarily store tasks when all threads in the thread pool are busy.
*/
public Queue getQueue() {
return queue;
}
/**
* Set a queue implementation that will be used to temporarily store tasks when all threads in the thread pool are
* busy.
*
* @param queue queue implementation that will be used to temporarily store tasks when all threads in the thread
* pool are busy.
* @return the {@link ThreadPoolConfig} with the new {@link java.util.Queue} implementation.
*/
public ThreadPoolConfig setQueue(Queue queue) {
this.queue = queue;
return this;
}
/**
* Return {@link java.util.concurrent.ThreadFactory} that will be used to create thread pool threads.
*
* If {@link java.util.concurrent.ThreadFactory} is set, then {@link #priority}, {@link #isDaemon},
* {@link #poolName} settings will not be considered when creating new threads.
*
* @return {@link java.util.concurrent.ThreadFactory} that will be used to create thread pool threads.
*/
public ThreadFactory getThreadFactory() {
return threadFactory;
}
/**
* Set {@link java.util.concurrent.ThreadFactory} that will be used to create thread pool threads.
*
* @param threadFactory custom {@link java.util.concurrent.ThreadFactory} If
* {@link java.util.concurrent.ThreadFactory} is set, then {@link #priority}, {@link
* #isDaemon}, {@link #poolName} settings will not be considered when creating new threads.
* @return the {@link ThreadPoolConfig} with the new {@link java.util.concurrent.ThreadFactory}
*/
public ThreadPoolConfig setThreadFactory(ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
return this;
}
/**
* Return thread pool name. The default is "Tyrus-client".
*
* @return the thread pool name.
*/
public String getPoolName() {
return poolName;
}
/**
* Set thread pool name. The default is "Tyrus-client".
*
* @param poolName the thread pool name.
* @return the {@link ThreadPoolConfig} with the new thread pool name.
*/
public ThreadPoolConfig setPoolName(String poolName) {
this.poolName = poolName;
return this;
}
/**
* Get priority of the threads in thread pool. The default is {@link Thread#NORM_PRIORITY}.
*
* @return priority of the threads in thread pool.
*/
public int getPriority() {
return priority;
}
/**
* Set priority of the threads in thread pool. The default is {@link Thread#NORM_PRIORITY}.
*
* @param priority of the threads in thread pool.
* @return the {@link ThreadPoolConfig} with the new thread priority.
*/
public ThreadPoolConfig setPriority(int priority) {
this.priority = priority;
return this;
}
/**
* Return {@code true} if thread pool threads are daemons. The default is {@code true}.
*
* @return {@code true} if thread pool threads are daemons.
*/
public boolean isDaemon() {
return isDaemon;
}
/**
* Set {@code true} if thread pool threads are daemons. The default is {@code true}.
*
* @param isDaemon {@code true} if thread pool threads are daemons.
* @return the {@link ThreadPoolConfig} with the daemon property set.
*/
public ThreadPoolConfig setDaemon(boolean isDaemon) {
this.isDaemon = isDaemon;
return this;
}
/**
* Get max thread pool size. The default is {@code Math.max(Runtime.getRuntime().availableProcessors(), 20)}
*
* @return max thread pool size.
*/
public int getMaxPoolSize() {
return maxPoolSize;
}
/**
* Set max thread pool size. The default is The default is {@code
* Math.max(Runtime.getRuntime().availableProcessors(), 20)}.
*
* Cannot be smaller than 3.
*
* @param maxPoolSize the max thread pool size.
* @return the {@link ThreadPoolConfig} with the new max pool size set.
*/
public ThreadPoolConfig setMaxPoolSize(int maxPoolSize) {
if (maxPoolSize < 3) {
throw new IllegalArgumentException("Max thread pool size cannot be smaller than 3");
}
this.maxPoolSize = maxPoolSize;
return this;
}
/**
* Get the core thread pool size - the size of the thread pool will never bee smaller than this.
*
* The default is 1.
*
* @return the core thread pool size - the size of the thread pool will never bee smaller than this.
*/
public int getCorePoolSize() {
return corePoolSize;
}
/**
* Set the core thread pool size - the size of the thread pool will never bee smaller than this.
*
* The default is 1.
*
* @param corePoolSize the core thread pool size - the size of the thread pool will never bee smaller than this.
* @return the {@link ThreadPoolConfig} with the new core pool size set.
*/
public ThreadPoolConfig setCorePoolSize(int corePoolSize) {
if (corePoolSize < 0) {
throw new IllegalArgumentException("Core thread pool size cannot be smaller than 0");
}
this.corePoolSize = corePoolSize;
return this;
}
/**
* Get the limit of the queue, where tasks are temporarily stored when all threads are busy.
*
* Value less than 0 means unlimited queue. The default is -1.
*
* @return the thread-pool queue limit. The queue limit
*/
public int getQueueLimit() {
return queueLimit;
}
/**
* Set the limit of the queue, where tasks are temporarily stored when all threads are busy.
*
* Value less than 0 means unlimited queue. The default is -1.
*
* @param queueLimit the thread pool queue limit. The queueLimit
value less than 0 means unlimited queue.
* @return the {@link ThreadPoolConfig} with the new queue limit.
*/
public ThreadPoolConfig setQueueLimit(int queueLimit) {
if (queueLimit < 0) {
this.queueLimit = -1;
} else {
this.queueLimit = queueLimit;
}
return this;
}
/**
* The max period of time a thread will wait for a new task to process.
*
* If the timeout expires and the thread is not a core one (see {@link #setCorePoolSize(int)},
* {@link #setMaxPoolSize(int)}) - then the thread will be terminated and removed from the thread pool.
*
* The default is 10s.
*
* @param time max keep alive timeout. The value less than 0 means no timeout.
* @param unit time unit.
* @return the {@link ThreadPoolConfig} with the new keep alive time.
*/
public ThreadPoolConfig setKeepAliveTime(long time, TimeUnit unit) {
if (time < 0) {
keepAliveTimeMillis = -1;
} else {
keepAliveTimeMillis = TimeUnit.MILLISECONDS.convert(time, unit);
}
return this;
}
/**
* Get the max period of time a thread will wait for a new task to process.
*
* If the timeout expires and the thread is not a core one (see {@link #setCorePoolSize(int)}, {@link
* #setMaxPoolSize(int)}) - then the thread will be terminated and removed from the thread pool.
*
* The default is 10s.
*
* @param timeUnit time unit to which the result will be converted.
* @return the keep-alive timeout, the value less than 0 means no timeout.
*/
public long getKeepAliveTime(TimeUnit timeUnit) {
if (keepAliveTimeMillis == -1) {
return -1;
}
return timeUnit.convert(keepAliveTimeMillis, TimeUnit.MILLISECONDS);
}
/**
* Get the class loader (if any) to be initially exposed by threads from this pool.
*
* If not specified, the class loader of the parent thread that initialized the pool will be used.Authen
*
* @return the class loader (if any) to be initially exposed by threads from this pool.
*/
public ClassLoader getInitialClassLoader() {
return initialClassLoader;
}
/**
* Specifies the context class loader that will be used by threads in this pool.
*
* If not specified, the class loader of the parent thread that initialized the pool will be used.
*
* @param initialClassLoader the class loader to be exposed by threads of this pool.
* @return the {@link ThreadPoolConfig} with the class loader set.
* @see Thread#getContextClassLoader()
*/
public ThreadPoolConfig setInitialClassLoader(final ClassLoader initialClassLoader) {
this.initialClassLoader = initialClassLoader;
return this;
}
@Override
public String toString() {
return ThreadPoolConfig.class.getSimpleName() + " :\r\n"
+ " poolName: " + poolName + "\r\n"
+ " corePoolSize: " + corePoolSize + "\r\n"
+ " maxPoolSize: " + maxPoolSize + "\r\n"
+ " queue: " + (queue != null ? queue.getClass() : "undefined") + "\r\n"
+ " queueLimit: " + queueLimit + "\r\n"
+ " keepAliveTime (millis): " + keepAliveTimeMillis + "\r\n"
+ " threadFactory: " + threadFactory + "\r\n"
+ " priority: " + priority + "\r\n"
+ " isDaemon: " + isDaemon + "\r\n"
+ " initialClassLoader: " + initialClassLoader;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ThreadPoolConfig that = (ThreadPoolConfig) o;
if (corePoolSize != that.corePoolSize) {
return false;
}
if (isDaemon != that.isDaemon) {
return false;
}
if (keepAliveTimeMillis != that.keepAliveTimeMillis) {
return false;
}
if (maxPoolSize != that.maxPoolSize) {
return false;
}
if (priority != that.priority) {
return false;
}
if (queueLimit != that.queueLimit) {
return false;
}
if (initialClassLoader != null ? !initialClassLoader.equals(that.initialClassLoader)
: that.initialClassLoader != null) {
return false;
}
if (poolName != null ? !poolName.equals(that.poolName) : that.poolName != null) {
return false;
}
if (queue != null ? !queue.equals(that.queue) : that.queue != null) {
return false;
}
if (threadFactory != null ? !threadFactory.equals(that.threadFactory) : that.threadFactory != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = poolName != null ? poolName.hashCode() : 0;
result = 31 * result + corePoolSize;
result = 31 * result + maxPoolSize;
result = 31 * result + (queue != null ? queue.hashCode() : 0);
result = 31 * result + queueLimit;
result = 31 * result + (int) (keepAliveTimeMillis ^ (keepAliveTimeMillis >>> 32));
result = 31 * result + (threadFactory != null ? threadFactory.hashCode() : 0);
result = 31 * result + priority;
result = 31 * result + (isDaemon ? 1 : 0);
result = 31 * result + (initialClassLoader != null ? initialClassLoader.hashCode() : 0);
return result;
}
}