Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright (C) 2012 Ness Computing, Inc.
*
* 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 com.opentable.concurrent;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
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 java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.MetricRegistry;
import com.google.common.base.MoreObjects;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.mogwee.executors.LoggingExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.PropertyResolver;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.export.UnableToRegisterMBeanException;
import com.opentable.concurrent.ThreadPoolConfig.RejectedHandler;
import com.opentable.spring.SpecializedConfigFactory;
/**
* Builder for a configurable {@link ExecutorService}.
* @see ThreadPoolConfig Thread pool configuration options
*/
public class ThreadPoolBuilder implements FactoryBean
{
private static final Logger LOG = LoggerFactory.getLogger(ThreadPoolBuilder.class);
private final String threadPoolName;
private ThreadPoolConfig config;
private int defaultMinThreads = ThreadPoolConfig.DEFAULT_MIN_THREADS;
private int defaultMaxThreads = ThreadPoolConfig.DEFAULT_MAX_THREADS;
private Duration defaultTimeout = ThreadPoolConfig.DEFAULT_TIMEOUT;
private int defaultQueueSize = ThreadPoolConfig.DEFAULT_QUEUE_SIZE;
private RejectedExecutionHandler defaultRejectedHandler = ThreadPoolConfig.DEFAULT_REJECTED_HANDLER.getHandler();
private boolean threadDelegatingWrapperEnabled = true;
private MetricRegistry metricRegistry;
private MBeanExporter exporter;
private final List> wrapperSuppliers = new ArrayList<>();
ThreadPoolBuilder(String threadPoolName)
{
this.threadPoolName = threadPoolName;
}
/**
* Create a default thread pool.
*/
public static ThreadPoolBuilder defaultPool(String threadPoolName)
{
return new ThreadPoolBuilder(threadPoolName);
}
/**
* Create a thread pool for long-running tasks. The default settings will change to not have a
* run queue.
*/
public static ThreadPoolBuilder longTaskPool(String threadPoolName, int poolSize)
{
return new ThreadPoolBuilder(threadPoolName).withDefaultMaxThreads(poolSize).withDefaultQueueSize(0);
}
/**
* Create a thread pool for short-running tasks. The default settings will change to have one thread
* available per core, plus a few to pick up slack.
*/
public static ThreadPoolBuilder shortTaskPool(String threadPoolName, int queueSize)
{
return new ThreadPoolBuilder(threadPoolName).withDefaultMaxThreads(Runtime.getRuntime().availableProcessors() + 2).withDefaultQueueSize(queueSize);
}
/**
* (For Spring) Inject the property resolver to generate the configuration for the builder according to its name.
*/
@Inject
public ThreadPoolBuilder withConfig(PropertyResolver pr) {
return withConfig(SpecializedConfigFactory.create(pr, ThreadPoolConfig.class, "ot.threadPool.${name}")
.apply(threadPoolName));
}
/**
* Set the configuration.
*/
public ThreadPoolBuilder withConfig(ThreadPoolConfig config) {
this.config = config;
return this;
}
/**
* Set the default pool core thread count.
*/
public ThreadPoolBuilder withDefaultMinThreads(int newDefaultMinThreads)
{
this.defaultMinThreads = newDefaultMinThreads;
return this;
}
/**
* Set the default pool max thread count. May be 0, in which case the executor will be a
* {@link MoreExecutors#newDirectExecutorService()}.
*/
public ThreadPoolBuilder withDefaultMaxThreads(int newDefaultMaxThreads)
{
this.defaultMaxThreads = newDefaultMaxThreads;
return this;
}
/**
* Set the default worker thread idle timeout.
*/
public ThreadPoolBuilder withDefaultThreadTimeout(Duration defaultTimeout)
{
this.defaultTimeout = defaultTimeout;
return this;
}
/**
* Set the default queue length. May be 0, in which case the queue will be a
* {@link SynchronousQueue}.
*/
public ThreadPoolBuilder withDefaultQueueSize(int newDefaultQueueSize)
{
this.defaultQueueSize = newDefaultQueueSize;
return this;
}
/**
* Set the default rejected execution handler.
*/
public ThreadPoolBuilder withDefaultRejectedHandler(RejectedExecutionHandler newDefaultRejectedHandler)
{
this.defaultRejectedHandler = newDefaultRejectedHandler;
return this;
}
/**
* Remove thread delegated wrapper.
*/
public ThreadPoolBuilder disableThreadDelegation()
{
this.threadDelegatingWrapperEnabled = false;
return this;
}
/**
* Enable timing wrapper by providing metrics registry into which to put timings and other related metrics.
*/
@Autowired(required=false)
public ThreadPoolBuilder enableTimingWrapper(MetricRegistry metricRegistry) {
this.metricRegistry = metricRegistry;
return this;
}
/**
* Add a callable wrapper.
*/
public ThreadPoolBuilder addCallableWrapper(Supplier callableWrapperSupplier) {
wrapperSuppliers.add(callableWrapperSupplier);
return this;
}
/**
* Expose some management abilities through JMX.
*/
@Autowired(required=false)
public ThreadPoolBuilder withJmxManagement(MBeanExporter exporter) {
this.exporter = exporter;
return this;
}
/**
* @return Executor service based on thus-configured properties. Includes management.
*/
public ExecutorService build() {
Integer queueSize = MoreObjects.firstNonNull(config == null ? null : config.getQueueSize(), defaultQueueSize);
Integer minThreads = MoreObjects.firstNonNull(config == null ? null : config.getMinThreads(), defaultMinThreads);
Integer maxThreads = MoreObjects.firstNonNull(config == null ? null : config.getMaxThreads(), defaultMaxThreads);
Duration threadTimeout = MoreObjects.firstNonNull(config == null ? null : config.getThreadTimeout(), defaultTimeout);
RejectedHandler rejectedHandlerEnum = config == null ? null : config.getRejectedHandler();
RejectedExecutionHandler rejectedHandler = rejectedHandlerEnum != null ? rejectedHandlerEnum.getHandler() : defaultRejectedHandler;
List wrappers = new ArrayList<>();
if (metricRegistry != null) {
wrappers.add(new TimerWrapper(threadPoolName, metricRegistry));
}
if (threadDelegatingWrapperEnabled) {
wrappers.add(ThreadDelegatingDecorator.THREAD_DELEGATING_WRAPPER);
}
wrappers.addAll(wrapperSuppliers.stream().map(Supplier::get).collect(Collectors.toList()));
final BlockingQueue queue;
final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(threadPoolName + "-%d").build();
if (queueSize == 0) {
queue = new SynchronousQueue<>();
} else {
queue = new LinkedBlockingQueue<>(queueSize);
}
final ExecutorService result;
final ExecutorServiceManagementBean management;
if (maxThreads <= 0) {
result = MoreExecutors.newDirectExecutorService();
management = new GenericExecutorManagementBean(threadPoolName, result, new SynchronousQueue<>());
} else {
ThreadPoolExecutor executor = new LoggingExecutor(
minThreads,
maxThreads,
threadTimeout.toMillis(),
TimeUnit.MILLISECONDS,
queue,
threadFactory,
rejectedHandler);
management = new ThreadPoolExecutorManagementBean(threadPoolName, executor);
result = executor;
}
if (metricRegistry != null) {
metricRegistry.registerAll(management);
}
final ObjectName objectName;
try {
objectName = new ObjectName(
"com.opentable.concurrent:type=executor,name=" + threadPoolName);
} catch (MalformedObjectNameException e) {
throw Throwables.propagate(e);
}
if (exporter != null) {
try {
exporter.registerManagedResource(management, objectName);
LOG.info("Exported JMX for thread pool {} at '{}'", threadPoolName, objectName);
} catch (UnableToRegisterMBeanException e) {
LOG.error("Unable to export thread pool '{}' as '{}'", threadPoolName, objectName, e);
}
} else {
LOG.debug("Not exporting JMX statistics");
}
final Runnable cleanup = () -> {
if (exporter != null) {
exporter.unregisterManagedResource(objectName);
}
if (metricRegistry != null) {
final Map exportedMetrics = management.getMetrics();
final MetricFilter exported = (name, metric) -> exportedMetrics.containsKey(name);
metricRegistry.removeMatching(exported);
}
};
final ExecutorService decorated = DecoratingExecutors.decorate(result, CallableWrappers.combine(wrappers));
return new CleanupExecutorService(decorated, cleanup);
}
@Override
public ExecutorService getObject() throws Exception {
return build();
}
@Override
public Class> getObjectType() {
return ExecutorService.class;
}
@Override
public boolean isSingleton() {
return true;
}
}