背景
在生产环境,有时候因为代码bug或者数据量太大,导致某个线程死循环或者耗时非常长线程hang住了。在一些场景下,我们希望可以在不重启服务的情况下把这些线程终止了。
在 ActiveMQ 源码中发现一个通过线程名stop线程的方法,在此分享出来供参考。
代码
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
public class ThreadExplorer
{
static Logger logger = Logger.getLogger(ThreadExplorer.class);
public static Thread[] listThreads()
{
int nThreads = Thread.activeCount();
Thread ret[] = new Thread[nThreads];
Thread.enumerate(ret);
return ret;
}
/**
* Helper function to access a thread per name (ignoring case)
*
* @param name
* @return
*/
public static Thread fetchThread(String name)
{
Thread[] threadArray = listThreads();
// for (Thread t : threadArray)
for (int i = 0; i < threadArray.length; i++)
{
Thread t = threadArray[i];
if (t.getName().equalsIgnoreCase(name))
return t;
}
return null;
}
/**
* Allow for killing threads
*
* @param threadName
* @param isStarredExp
* (regular expressions with *)
*/
@SuppressWarnings("deprecation")
public static int kill(String threadName, boolean isStarredExp)
{
String me = "ThreadExplorer.kill: ";
if (logger.isDebugEnabled())
{
logger.debug("Entering " + me + " with " + threadName + " isStarred: " + isStarredExp);
}
int ret = 0;
Pattern mypattern = null;
if (isStarredExp)
{
String realreg = threadName.toLowerCase().replaceAll("\\*", "\\.\\*");
mypattern = Pattern.compile(realreg);
}
Thread[] threads = listThreads();
for (int i = 0; i < threads.length; i++)
{
Thread thread = threads[i];
if (thread == null)
continue;
// kill the thread unless it is not current thread
boolean matches = false;
if (isStarredExp)
{
Matcher matcher = mypattern.matcher(thread.getName().toLowerCase());
matches = matcher.matches();
}
else
{
matches = (thread.getName().equalsIgnoreCase(threadName));
}
if (matches && (Thread.currentThread() != thread) && !thread.getName().equals("main"))
{
if (logger.isInfoEnabled())
logger.info("Killing thread named [" + thread.getName() + "]"); // , removing its uncaught
ret++;
try
{
thread.stop();
}
catch (ThreadDeath e)
{
logger.warn("Thread already death.", e);
}
}
}
return ret;
}
public static String show(String title)
{
StringBuffer out = new StringBuffer();
Thread[] threadArray = ThreadExplorer.listThreads();
out.append(title + "\n");
for (int i = 0; i < threadArray.length; i++)
{
Thread thread = threadArray[i];
if (thread != null)
{
out.append("* [" + thread.getName() + "] " + (thread.isDaemon() ? "(Daemon)" : "")
+ " Group: " + thread.getThreadGroup().getName() + "\n");
}
else
{
out.append("* ThreadDeath: " + thread + "\n");
}
}
return out.toString();
}
public static int active()
{
int count = 0;
Thread[] threadArray = ThreadExplorer.listThreads();
for (int i = 0; i < threadArray.length; i++)
{
Thread thread = threadArray[i];
if (thread != null)
{
count++;
}
}
return count;
}
}
示例
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestMain {
public static void main(String[] args) throws IOException, InterruptedException {
ExecutorService threadPool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) { //10个线程死循环
int finalI = i;
threadPool.execute(() -> {
for (;;){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("中断Thread#=="+ finalI);
e.printStackTrace();
}
}
});
}
threadPool.shutdown();
System.out.println(ThreadExplorer.show("Kill thread 开始前线程#####"));
ThreadExplorer.kill("pool-1-thread-1", false, "");
ThreadExplorer.kill("pool-1-thread-3", false, "");
//ThreadExplorer.kill("pool-1-thread-*", truer, "");//stop所有线程名符合pool-1-thread-*的线程
Thread.sleep(1000);// 休眠只是为了后面能够打印的时候准确显示
System.out.println(ThreadExplorer.show("Kill thread 结束后剩余线程#####"));
}
}
示例结果
Kill thread 开始前线程#####
* [main] Group: main
* [pool-1-thread-1] Group: main
* [pool-1-thread-2] Group: main
* [pool-1-thread-3] Group: main
* [pool-1-thread-4] Group: main
* [pool-1-thread-5] Group: main
* [pool-1-thread-6] Group: main
* [pool-1-thread-7] Group: main
* [pool-1-thread-8] Group: main
* [pool-1-thread-9] Group: main
* [pool-1-thread-10] Group: main
Killing thread named [pool-1-thread-1]
Killing thread named [pool-1-thread-3]
Kill thread 结束后剩余线程#####
* [main] Group: main
* [pool-1-thread-2] Group: main
* [pool-1-thread-4] Group: main
* [pool-1-thread-5] Group: main
* [pool-1-thread-6] Group: main
* [pool-1-thread-7] Group: main
* [pool-1-thread-8] Group: main
* [pool-1-thread-9] Group: main
* [pool-1-thread-10] Group: main