io.github.hengyunabc.metrics.ThreadFactoryBuilder Maven / Gradle / Ivy
Show all versions of metrics-kafka Show documentation
/*
* Copyright (C) 2010 The Guava Authors
*
* 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 io.github.hengyunabc.metrics;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
/**
* From google guava.
* A ThreadFactory builder, providing any combination of these features:
*
* - whether threads should be marked as {@linkplain Thread#setDaemon daemon}
* threads
*
- a {@linkplain ThreadFactoryBuilder#setNameFormat naming format}
*
- a {@linkplain Thread#setPriority thread priority}
*
- an {@linkplain Thread#setUncaughtExceptionHandler uncaught exception
* handler}
*
- a {@linkplain ThreadFactory#newThread backing thread factory}
*
*
* If no backing thread factory is provided, a default backing thread factory is
* used as if by calling {@code setThreadFactory(}
* {@link Executors#defaultThreadFactory()}{@code )}.
*
* @author Kurt Alfred Kluever
* @since 4.0
*/
public final class ThreadFactoryBuilder {
private String nameFormat = null;
private Boolean daemon = null;
private Integer priority = null;
private UncaughtExceptionHandler uncaughtExceptionHandler = null;
private ThreadFactory backingThreadFactory = null;
/**
* Creates a new {@link ThreadFactory} builder.
*/
public ThreadFactoryBuilder() {
}
/**
* Sets the naming format to use when naming threads ({@link Thread#setName}
* ) which are created with this ThreadFactory.
*
* @param nameFormat
* a {@link String#format(String, Object...)}-compatible format
* String, to which a unique integer (0, 1, etc.) will be
* supplied as the single parameter. This integer will be unique
* to the built instance of the ThreadFactory and will be
* assigned sequentially. For example, {@code "rpc-pool-%d"} will
* generate thread names like {@code "rpc-pool-0"},
* {@code "rpc-pool-1"}, {@code "rpc-pool-2"}, etc.
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setNameFormat(String nameFormat) {
String.format(nameFormat, 0); // fail fast if the format is bad or null
this.nameFormat = nameFormat;
return this;
}
/**
* Sets daemon or not for new threads created with this ThreadFactory.
*
* @param daemon
* whether or not new Threads created with this ThreadFactory
* will be daemon threads
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setDaemon(boolean daemon) {
this.daemon = daemon;
return this;
}
/**
* Sets the priority for new threads created with this ThreadFactory.
*
* @param priority
* the priority for new Threads created with this ThreadFactory
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setPriority(int priority) {
// Thread#setPriority() already checks for validity. These error
// messages
// are nicer though and will fail-fast.
checkArgument(priority >= Thread.MIN_PRIORITY, "Thread priority (%s) must be >= %s", priority,
Thread.MIN_PRIORITY);
checkArgument(priority <= Thread.MAX_PRIORITY, "Thread priority (%s) must be <= %s", priority,
Thread.MAX_PRIORITY);
this.priority = priority;
return this;
}
/**
* Sets the {@link UncaughtExceptionHandler} for new threads created with
* this ThreadFactory.
*
* @param uncaughtExceptionHandler
* the uncaught exception handler for new Threads created with
* this ThreadFactory
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setUncaughtExceptionHandler(UncaughtExceptionHandler uncaughtExceptionHandler) {
this.uncaughtExceptionHandler = checkNotNull(uncaughtExceptionHandler);
return this;
}
/**
* Sets the backing {@link ThreadFactory} for new threads created with this
* ThreadFactory. Threads will be created by invoking #newThread(Runnable)
* on this backing {@link ThreadFactory}.
*
* @param backingThreadFactory
* the backing {@link ThreadFactory} which will be delegated to
* during thread creation.
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setThreadFactory(ThreadFactory backingThreadFactory) {
this.backingThreadFactory = checkNotNull(backingThreadFactory);
return this;
}
/**
* Returns a new thread factory using the options supplied during the
* building process. After building, it is still possible to change the
* options used to build the ThreadFactory and/or build again. State is not
* shared amongst built instances.
*
* @return the fully constructed {@link ThreadFactory}
*/
public ThreadFactory build() {
return build(this);
}
private static ThreadFactory build(ThreadFactoryBuilder builder) {
final String nameFormat = builder.nameFormat;
final Boolean daemon = builder.daemon;
final Integer priority = builder.priority;
final UncaughtExceptionHandler uncaughtExceptionHandler = builder.uncaughtExceptionHandler;
final ThreadFactory backingThreadFactory = (builder.backingThreadFactory != null) ? builder.backingThreadFactory
: Executors.defaultThreadFactory();
final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
return new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
Thread thread = backingThreadFactory.newThread(runnable);
if (nameFormat != null) {
thread.setName(String.format(nameFormat, count.getAndIncrement()));
}
if (daemon != null) {
thread.setDaemon(daemon);
}
if (priority != null) {
thread.setPriority(priority);
}
if (uncaughtExceptionHandler != null) {
thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
}
return thread;
}
};
}
/**
* Substitutes each {@code %s} in {@code template} with an argument. These
* are matched by position: the first {@code %s} gets {@code args[0]}, etc.
* If there are more arguments than placeholders, the unmatched arguments
* will be appended to the end of the formatted message in square braces.
*
* @param template
* a non-null string containing 0 or more {@code %s}
* placeholders.
* @param args
* the arguments to be substituted into the message template.
* Arguments are converted to strings using
* {@link String#valueOf(Object)}. Arguments can be null.
*/
// Note that this is somewhat-improperly used from Verify.java as well.
static String format(String template, Object... args) {
template = String.valueOf(template); // null -> "null"
// start substituting the arguments into the '%s' placeholders
StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
int templateStart = 0;
int i = 0;
while (i < args.length) {
int placeholderStart = template.indexOf("%s", templateStart);
if (placeholderStart == -1) {
break;
}
builder.append(template.substring(templateStart, placeholderStart));
builder.append(args[i++]);
templateStart = placeholderStart + 2;
}
builder.append(template.substring(templateStart));
// if we run out of placeholders, append the extra args in square braces
if (i < args.length) {
builder.append(" [");
builder.append(args[i++]);
while (i < args.length) {
builder.append(", ");
builder.append(args[i++]);
}
builder.append(']');
}
return builder.toString();
}
/**
* Ensures the truth of an expression involving one or more parameters to
* the calling method.
*
* @param expression
* a boolean expression
* @param errorMessageTemplate
* a template for the exception message should the check fail.
* The message is formed by replacing each {@code %s} placeholder
* in the template with an argument. These are matched by
* position - the first {@code %s} gets
* {@code errorMessageArgs[0]}, etc. Unmatched arguments will be
* appended to the formatted message in square braces. Unmatched
* placeholders will be left as-is.
* @param errorMessageArgs
* the arguments to be substituted into the message template.
* Arguments are converted to strings using
* {@link String#valueOf(Object)}.
* @throws IllegalArgumentException
* if {@code expression} is false
* @throws NullPointerException
* if the check fails and either {@code errorMessageTemplate} or
* {@code errorMessageArgs} is null (don't let this happen)
*/
private void checkArgument(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
if (!expression) {
throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageArgs));
}
}
/**
* Ensures that an object reference passed as a parameter to the calling
* method is not null.
*
* @param reference
* an object reference
* @return the non-null reference that was validated
* @throws NullPointerException
* if {@code reference} is null
*/
public static T checkNotNull(T reference) {
if (reference == null) {
throw new NullPointerException();
}
return reference;
}
}