All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.tsunami.common.concurrent.BaseThreadPoolModule Maven / Gradle / Ivy

There is a newer version: 0.0.26
Show newest version
/*
 * Copyright 2020 Google LLC
 *
 * 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.google.tsunami.common.concurrent;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.base.Strings;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.inject.AbstractModule;
import com.google.inject.Key;
import java.lang.annotation.Annotation;
import java.time.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
import java.util.concurrent.TimeUnit;
import javax.inject.Provider;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * The base module for binding a thread pool.
 *
 * 

This module is essentially a thin wrapper around {@link ThreadFactoryBuilder} and the * corresponding {@link ExecutorService} families. Based on the intended usage, it is expected that * subclasses of this module should provides bindings to a concrete thread pool implementation of * {@link ExecutorService}. This base module wraps the actual {@link ExecutorService} implementation * in order to support {@link com.google.common.util.concurrent.ListenableFuture} usage in the code * base. * * @param The expected thread pool implementation, must be a subclass of {@link * ListeningExecutorService}. */ abstract class BaseThreadPoolModule extends AbstractModule { private final ThreadFactory factory; private final int maxSize; private final int coreSize; private final long keepAliveSeconds; private final @Nullable Duration shutdownDelay; private final Key key; private final Class executorServiceTypeClass; private final RejectedExecutionHandler rejectedExecutionHandler; BaseThreadPoolModule(BaseThreadPoolModuleBuilder builder) { checkNotNull(builder); this.factory = builder.factoryBuilder.build(); this.maxSize = builder.maxSize; this.coreSize = builder.coreSize; this.keepAliveSeconds = builder.keepAliveSeconds; this.shutdownDelay = builder.daemon ? builder.shutdownDelay : null; this.key = builder.key; this.executorServiceTypeClass = builder.executorServiceTypeClass; this.rejectedExecutionHandler = builder.rejectedExecutionHandler; } @Override protected final void configure() { configureThreadPool(key); } /** Subclasses should override this method for providing Guice bindings. */ abstract void configureThreadPool(Key key); /** Base {@link Provider} implementation for providing the target thread pool. */ abstract class BaseThreadPoolProvider implements Provider { abstract ExecutorService createThreadPool( int coreSize, int maxSize, long keepAliveSeconds, ThreadFactory factory, RejectedExecutionHandler rejectedExecutionHandler); @Override public final ExecutorServiceT get() { ExecutorService service = createThreadPool(coreSize, maxSize, keepAliveSeconds, factory, rejectedExecutionHandler); if (shutdownDelay != null) { MoreExecutors.addDelayedShutdownHook( service, shutdownDelay.toMillis(), TimeUnit.MILLISECONDS); } return executorServiceTypeClass.cast(MoreExecutors.listeningDecorator(service)); } } /** Base Builder for {@link BaseThreadPoolModule}. */ abstract static class BaseThreadPoolModuleBuilder< ExecutorServiceT extends ListeningExecutorService, BuilderImplT extends BaseThreadPoolModuleBuilder> { protected final ThreadFactoryBuilder factoryBuilder = new ThreadFactoryBuilder(); protected String name; protected int maxSize; protected int coreSize; protected long keepAliveSeconds = 60L; protected boolean daemon; protected Duration shutdownDelay; protected Key key; protected final Class executorServiceTypeClass; protected RejectedExecutionHandler rejectedExecutionHandler = new AbortPolicy(); BaseThreadPoolModuleBuilder(Class executorServiceTypeClass) { this.executorServiceTypeClass = checkNotNull(executorServiceTypeClass); } abstract BuilderImplT self(); /** * Sets the name used to name the threads; automatically suffixed with "-%s"to incorporate the * thread number * * @param name the name of the thread pool. * @return the Builder instance itself. */ public BuilderImplT setName(String name) { checkArgument(!Strings.isNullOrEmpty(name), "Name should not be empty"); this.name = name; return self(); } /** * Sets the maximum number of threads allowed in the pool; value should be positive. * * @param maxSize the maximum number of threads allowed in this thread pool. * @return the Builder instance itself. */ BuilderImplT setMaxSize(int maxSize) { checkArgument(maxSize > 0, "Max thread pool size should be positive."); this.maxSize = maxSize; return self(); } /** * Sets the number of threads to keep in the pool. * * @param coreSize the minimum number of threads to keep alive in this thread pool. * @return the Builder instance itself. */ BuilderImplT setCoreSize(int coreSize) { checkArgument(coreSize >= 0, "The core pool size should be non-negative."); this.coreSize = coreSize; return self(); } /** * Sets the keep alive time in seconds for the threads not in core pool. * * @param keepAliveSeconds the maximum number of seconds an idle thread in this pool can keep * alive before being terminated. * @return the Builder instance itself. */ public BuilderImplT setKeepAliveSeconds(long keepAliveSeconds) { checkArgument(keepAliveSeconds >= 0, "The keep alive time should be non-negative."); this.keepAliveSeconds = keepAliveSeconds; return self(); } /** * Sets whether or not new threads created by the pool will be daemon threads.* * * @param daemon whether threads created in this pool are daemon threads. * @return the Builder instance itself. */ public BuilderImplT setDaemon(boolean daemon) { factoryBuilder.setDaemon(daemon); this.daemon = daemon; return self(); } /** * Sets how long the JVM should wait to exit for daemon threads to complete. * *

This has no effect if the pool does not use daemon threads. * * @param shutdownDelay the delay enforced during the thread pool shutdown. * @return the Builder instance itself. */ public BuilderImplT setDelayedShutdown(Duration shutdownDelay) { this.shutdownDelay = checkNotNull(shutdownDelay); return self(); } /** * Sets the priority for threads created by the pool. * * @param priority the priority of the threads created by this pool. * @return the Builder instance itself. */ public BuilderImplT setPriority(int priority) { factoryBuilder.setPriority(priority); return self(); } /** * Sets the binding annotation. * * @param annotation the Guice binding annotation for this thread pool. * @return the Builder instance itself. */ public BuilderImplT setAnnotation(Annotation annotation) { key = Key.get(executorServiceTypeClass, checkNotNull(annotation)); return self(); } /** * Sets the binding annotation. * * @param annotationClass the Guice binding annotation class for this thread pool. * @return the Builder instance itself. */ public BuilderImplT setAnnotation(Class annotationClass) { key = Key.get(executorServiceTypeClass, checkNotNull(annotationClass)); return self(); } /** * Sets the handler to use when thread execution is blocked due to thread bounds and queue * capacities are reached. * *

By default, {@link AbortPolicy} is used for rejected execution, which throws the {@link * java.util.concurrent.RejectedExecutionException}. * * @param rejectedExecutionHandler A handler for tasks that cannot be executed by this thread * pool. * @return the Builder instance itself. */ public BuilderImplT setRejectedExecutionHandler( RejectedExecutionHandler rejectedExecutionHandler) { this.rejectedExecutionHandler = checkNotNull(rejectedExecutionHandler); return self(); } final void validateAll() { checkState(!Strings.isNullOrEmpty(name), "Name is required."); checkState( maxSize > 0, "Max thread pool size must be positive. Did you forget setting maximum thread pool size" + " by calling setMaxSize?"); checkState( coreSize <= maxSize, "Thread pool core size should be less than or equal to max size."); checkState(key != null, "Annotation is required."); validate(); } abstract void validate(); public final AbstractModule build() { validateAll(); return newModule(); } abstract AbstractModule newModule(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy