/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2012 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2012 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is 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, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) 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 OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.core.concurrent; import java.util.BitSet; import java.util.concurrent.ThreadFactory; import org.opennms.core.utils.ThreadCategory; public class LogPreservingThreadFactory implements ThreadFactory { private final BitSet m_slotNumbers; private final String m_name; private final int m_poolSize; private String m_logPrefix = null; private int m_counter = 0; public LogPreservingThreadFactory(String poolName, int poolSize, boolean preserveLogPrefix) { m_name = poolName; m_poolSize = poolSize; // Make the bitset of thread numbers one larger so that we can 1-index it. // If pool size is Integer.MAX_VALUE, then the BitSet will not be used. m_slotNumbers = poolSize < Integer.MAX_VALUE ? new BitSet(poolSize + 1) : new BitSet(1); if (preserveLogPrefix) { m_logPrefix = ThreadCategory.getPrefix(); } } @Override public Thread newThread(final Runnable r) { if (m_poolSize == Integer.MAX_VALUE) { return getIncrementingThread(r); } else if (m_poolSize > 1) { return getPooledThread(r); } else { return getSingleThread(r); } } private Thread getIncrementingThread(final Runnable r) { String name = String.format("%s-Thread-%d", m_name, ++m_counter); return new Thread(new Runnable() { @Override public void run() { // Set the logging prefix if it was stored during creation if (m_logPrefix != null) { ThreadCategory.setPrefix(m_logPrefix); } // Run the delegate Runnable r.run(); } }, name); } private Thread getSingleThread(final Runnable r) { String name = String.format("%s-Thread", m_name); return new Thread(new Runnable() { @Override public void run() { // Set the logging prefix if it was stored during creation if (m_logPrefix != null) { ThreadCategory.setPrefix(m_logPrefix); } // Run the delegate Runnable r.run(); } }, name); } private Thread getPooledThread(final Runnable r) { final int threadNumber = getOpenThreadSlot(m_slotNumbers); String name = String.format("%s-Thread-%d-of-%d", m_name, threadNumber, m_poolSize); return new Thread(new Runnable() { @Override public void run() { try { // Set the logging prefix if it was stored during creation if (m_logPrefix != null) { ThreadCategory.setPrefix(m_logPrefix); } // Run the delegate Runnable r.run(); } finally { // And make sure the mark the thread as unused afterwards if // the thread ever exits synchronized(m_slotNumbers) { m_slotNumbers.set(threadNumber, false); } } } }, name); } private static int getOpenThreadSlot(BitSet bs) { synchronized(bs) { // Start at 1 so that we always return a positive integer for (int i = 1; i < bs.size(); i++) { if (bs.get(i)) { continue; } else { bs.set(i, true); return i; } } // We should never return zero return 0; } } }