Java tutorial
/* * Universal Media Server, for streaming any media to DLNA * compatible renderers based on the http://www.ps3mediaserver.org. * Copyright (C) 2012 UMS developers. * * This program is a free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; version 2 * of the License only. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package net.pms.util; import static org.apache.commons.lang3.StringUtils.isBlank; import java.util.Locale; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** * A {@link ThreadFactory} implementing a simple name structure. * * @author Nadahar */ public class BasicThreadFactory implements ThreadFactory { /** A static thread-safe pool number counter. */ protected static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); /** The pool number for this instance. */ protected final int instancePoolNumber; /** The {@link ThreadGroup}. */ protected final ThreadGroup group; /** The thread number counter. */ protected final AtomicInteger threadNumber = new AtomicInteger(1); /** The thread priority. */ protected final int threadPriority; /** The name pattern. */ protected final String namePattern; /** The number of variables in {@code namePattern}. */ protected final int numVariables; /** * Creates a new {@link BasicThreadFactory} using the default * {@link ThreadGroup} and priority {@link Thread#NORM_PRIORITY}. * <p> * The {@link Thread} names generated by the new {@link BasicThreadFactory} * is created by calling {@link String#format} with {@code namePattern} as * the "format" and pool- and thread number as arguments. The formatting * rules are those of {@link java.util.Formatter}. * <p> * No more than two variables of type {@code %d} or {@code %s} is allowed in * {@code namePattern}, and they will be substituted as follows: * <ul> * <li>No variables: All {@link Thread} names generated by this * {@link ThreadFactory} will be equal to {@code namePattern}.</li> * <li>One variable: Only thread number will be used, pool number isn't * used.</li> * <li>Two variables: Pool number will be used for the first variable in * {@code namePattern}, thread number for the second. * </ul> * * @param namePattern The {@link java.util.Formatter} formatted * {@link String} from which to generate {@link Thread} names. */ public BasicThreadFactory(String namePattern) { this(namePattern, Thread.NORM_PRIORITY, null); } /** * Creates a new {@link BasicThreadFactory} using the given arguments and * the default {@link ThreadGroup}. * <p> * The {@link Thread} names generated by the new {@link BasicThreadFactory} * is created by calling {@link String#format} with {@code namePattern} as * the "format" and pool- and thread number as arguments. The formatting * rules are those of {@link java.util.Formatter}. * <p> * No more than two variables of type {@code %d} or {@code %s} is allowed in * {@code namePattern}, and they will be substituted as follows: * <ul> * <li>No variables: All {@link Thread} names generated by this * {@link ThreadFactory} will be equal to {@code namePattern}.</li> * <li>One variable: Only thread number will be used, pool number isn't * used.</li> * <li>Two variables: Pool number will be used for the first variable in * {@code namePattern}, thread number for the second. * </ul> * * @param namePattern The {@link java.util.Formatter} formatted * {@link String} from which to generate {@link Thread} names. * @param threadPriority The {@link Thread} priority. */ public BasicThreadFactory(String namePattern, int threadPriority) { this(namePattern, threadPriority, null); } /** * Creates a new {@link BasicThreadFactory} using the given arguments and * priority {@link Thread#NORM_PRIORITY}. * <p> * The {@link Thread} names generated by the new {@link BasicThreadFactory} * is created by calling {@link String#format} with {@code namePattern} as * the "format" and pool- and thread number as arguments. The formatting * rules are those of {@link java.util.Formatter}. * <p> * No more than two variables of type {@code %d} or {@code %s} is allowed in * {@code namePattern}, and they will be substituted as follows: * <ul> * <li>No variables: All {@link Thread} names generated by this * {@link ThreadFactory} will be equal to {@code namePattern}.</li> * <li>One variable: Only thread number will be used, pool number isn't * used.</li> * <li>Two variables: Pool number will be used for the first variable in * {@code namePattern}, thread number for the second. * </ul> * * @param namePattern The {@link java.util.Formatter} formatted * {@link String} from which to generate {@link Thread} names. * @param group The {@link ThreadGroup}. */ public BasicThreadFactory(String namePattern, ThreadGroup group) { this(namePattern, Thread.NORM_PRIORITY, group); } /** * Creates a new {@link BasicThreadFactory} using the given arguments. * <p> * The {@link Thread} names generated by the new {@link BasicThreadFactory} * is created by calling {@link String#format} with {@code namePattern} as * the "format" and pool- and thread number as arguments. The formatting * rules are those of {@link java.util.Formatter}. * <p> * No more than two variables of type {@code %d} or {@code %s} is allowed in * {@code namePattern}, and they will be substituted as follows: * <ul> * <li>No variables: All {@link Thread} names generated by this * {@link ThreadFactory} will be equal to {@code namePattern}.</li> * <li>One variable: Only thread number will be used, pool number isn't * used.</li> * <li>Two variables: Pool number will be used for the first variable in * {@code namePattern}, thread number for the second. * </ul> * * @param namePattern The {@link java.util.Formatter} formatted * {@link String} from which to generate {@link Thread} names. * @param threadPriority The {@link Thread} priority. * @param group The {@link ThreadGroup}. */ public BasicThreadFactory(String namePattern, int threadPriority, ThreadGroup group) { if (isBlank(namePattern)) { throw new IllegalArgumentException("namePattern cannot be blank"); } if (group == null) { SecurityManager securityManager = System.getSecurityManager(); group = (securityManager != null) ? securityManager.getThreadGroup() : Thread.currentThread().getThreadGroup(); } this.group = group; this.threadPriority = Math.min(Thread.MAX_PRIORITY, Math.max(Thread.MIN_PRIORITY, threadPriority)); int pctSes = 0; int pctDs = 0; int i = 0; while (true) { i = namePattern.indexOf("%s", i); if (i >= 0) { pctSes++; i++; } else { break; } } while (true) { i = namePattern.indexOf("%d", i); if (i >= 0) { pctDs++; i++; } else { break; } } if (pctSes + pctDs > 2) { throw new IllegalArgumentException("namePattern can't have more than 2 variables"); } this.numVariables = pctSes + pctDs; this.namePattern = namePattern; if (numVariables == 2) { this.instancePoolNumber = POOL_NUMBER.getAndIncrement(); } else { this.instancePoolNumber = 0; } } @Override public Thread newThread(Runnable runnable) { String threadName; switch (numVariables) { case 0: threadName = namePattern; break; case 1: threadName = String.format(Locale.ROOT, namePattern, threadNumber.getAndIncrement()); break; default: threadName = String.format(Locale.ROOT, namePattern, instancePoolNumber, threadNumber.getAndIncrement()); } Thread thread = new Thread(group, runnable, threadName, 0); if (thread.isDaemon()) { thread.setDaemon(false); } if (thread.getPriority() != threadPriority) { thread.setPriority(threadPriority); } return thread; } }