001 /* 002 * Copyright (C) 2010 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package com.google.common.util.concurrent; 018 019 import static com.google.common.base.Preconditions.checkArgument; 020 import static com.google.common.base.Preconditions.checkNotNull; 021 022 import java.lang.Thread.UncaughtExceptionHandler; 023 import java.util.concurrent.Executors; 024 import java.util.concurrent.ThreadFactory; 025 import java.util.concurrent.atomic.AtomicLong; 026 027 /** 028 * A ThreadFactory builder, providing any combination of these features: 029 * <ul> 030 * <li> whether threads should be marked as {@linkplain Thread#setDaemon daemon} 031 * threads 032 * <li> a {@linkplain ThreadFactoryBuilder#setNameFormat naming format} 033 * <li> a {@linkplain Thread#setPriority thread priority} 034 * <li> an {@linkplain Thread#setUncaughtExceptionHandler uncaught exception 035 * handler} 036 * <li> a {@linkplain ThreadFactory#newThread backing thread factory} 037 * </ul> 038 * If no backing thread factory is provided, a default backing thread factory is 039 * used as if by calling {@code setThreadFactory(}{@link 040 * Executors#defaultThreadFactory()}{@code )}. 041 * 042 * @author Kurt Alfred Kluever 043 * @since 4.0 044 */ 045 public final class ThreadFactoryBuilder { 046 private String nameFormat = null; 047 private Boolean daemon = null; 048 private Integer priority = null; 049 private UncaughtExceptionHandler uncaughtExceptionHandler = null; 050 private ThreadFactory backingThreadFactory = null; 051 052 /** 053 * Creates a new {@link ThreadFactory} builder. 054 */ 055 public ThreadFactoryBuilder() {} 056 057 /** 058 * Sets the naming format to use when naming threads ({@link Thread#setName}) 059 * which are created with this ThreadFactory. 060 * 061 * @param nameFormat a {@link String#format(String, Object...)}-compatible 062 * format String, to which a unique integer (0, 1, etc.) will be supplied 063 * as the single parameter. This integer will be unique to the built 064 * instance of the ThreadFactory and will be assigned sequentially. 065 * @return this for the builder pattern 066 */ 067 public ThreadFactoryBuilder setNameFormat(String nameFormat) { 068 String.format(nameFormat, 0); // fail fast if the format is bad or null 069 this.nameFormat = nameFormat; 070 return this; 071 } 072 073 /** 074 * Sets daemon or not for new threads created with this ThreadFactory. 075 * 076 * @param daemon whether or not new Threads created with this ThreadFactory 077 * will be daemon threads 078 * @return this for the builder pattern 079 */ 080 public ThreadFactoryBuilder setDaemon(boolean daemon) { 081 this.daemon = daemon; 082 return this; 083 } 084 085 /** 086 * Sets the priority for new threads created with this ThreadFactory. 087 * 088 * @param priority the priority for new Threads created with this 089 * ThreadFactory 090 * @return this for the builder pattern 091 */ 092 public ThreadFactoryBuilder setPriority(int priority) { 093 // Thread#setPriority() already checks for validity. These error messages 094 // are nicer though and will fail-fast. 095 checkArgument(priority >= Thread.MIN_PRIORITY, 096 "Thread priority (%s) must be >= %s", priority, Thread.MIN_PRIORITY); 097 checkArgument(priority <= Thread.MAX_PRIORITY, 098 "Thread priority (%s) must be <= %s", priority, Thread.MAX_PRIORITY); 099 this.priority = priority; 100 return this; 101 } 102 103 /** 104 * Sets the {@link UncaughtExceptionHandler} for new threads created with this 105 * ThreadFactory. 106 * 107 * @param uncaughtExceptionHandler the uncaught exception handler for new 108 * Threads created with this ThreadFactory 109 * @return this for the builder pattern 110 */ 111 public ThreadFactoryBuilder setUncaughtExceptionHandler( 112 UncaughtExceptionHandler uncaughtExceptionHandler) { 113 this.uncaughtExceptionHandler = checkNotNull(uncaughtExceptionHandler); 114 return this; 115 } 116 117 /** 118 * Sets the backing {@link ThreadFactory} for new threads created with this 119 * ThreadFactory. Threads will be created by invoking #newThread(Runnable) on 120 * this backing {@link ThreadFactory}. 121 * 122 * @param backingThreadFactory the backing {@link ThreadFactory} which will 123 * be delegated to during thread creation. 124 * @return this for the builder pattern 125 * 126 * @see MoreExecutors 127 */ 128 public ThreadFactoryBuilder setThreadFactory( 129 ThreadFactory backingThreadFactory) { 130 this.backingThreadFactory = checkNotNull(backingThreadFactory); 131 return this; 132 } 133 134 /** 135 * Returns a new thread factory using the options supplied during the building 136 * process. After building, it is still possible to change the options used to 137 * build the ThreadFactory and/or build again. State is not shared amongst 138 * built instances. 139 * 140 * @return the fully constructed {@link ThreadFactory} 141 */ 142 public ThreadFactory build() { 143 return build(this); 144 } 145 146 private static ThreadFactory build(ThreadFactoryBuilder builder) { 147 final String nameFormat = builder.nameFormat; 148 final Boolean daemon = builder.daemon; 149 final Integer priority = builder.priority; 150 final UncaughtExceptionHandler uncaughtExceptionHandler = 151 builder.uncaughtExceptionHandler; 152 final ThreadFactory backingThreadFactory = 153 (builder.backingThreadFactory != null) 154 ? builder.backingThreadFactory 155 : Executors.defaultThreadFactory(); 156 final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null; 157 return new ThreadFactory() { 158 @Override public Thread newThread(Runnable runnable) { 159 Thread thread = backingThreadFactory.newThread(runnable); 160 if (nameFormat != null) { 161 thread.setName(String.format(nameFormat, count.getAndIncrement())); 162 } 163 if (daemon != null) { 164 thread.setDaemon(daemon); 165 } 166 if (priority != null) { 167 thread.setPriority(priority); 168 } 169 if (uncaughtExceptionHandler != null) { 170 thread.setUncaughtExceptionHandler(uncaughtExceptionHandler); 171 } 172 return thread; 173 } 174 }; 175 } 176 }