From 735ec2e0b5f7006865b0ee8f1abac20e0299eed5 Mon Sep 17 00:00:00 2001 From: GGGGGHT Date: Wed, 19 Apr 2023 19:24:00 +0800 Subject: [PATCH] vmtool command support interrupt thread. #2427 --- .../src/main/java/arthas/VmTool.java | 13 +++++++++ .../src/main/java/arthas/VmToolMXBean.java | 7 +++++ .../src/test/java/arthas/VmToolTest.java | 28 +++++++++++++++++++ .../command/monitor200/VmToolCommand.java | 17 +++++++++-- 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/arthas-vmtool/src/main/java/arthas/VmTool.java b/arthas-vmtool/src/main/java/arthas/VmTool.java index 866d47ecb..19d2c6c0b 100644 --- a/arthas-vmtool/src/main/java/arthas/VmTool.java +++ b/arthas-vmtool/src/main/java/arthas/VmTool.java @@ -1,5 +1,7 @@ package arthas; +import java.util.Map; + /** * @author ZhangZiCheng 2021-02-12 * @author hengyunabc 2021-04-26 @@ -70,6 +72,17 @@ public class VmTool implements VmToolMXBean { forceGc0(); } + @Override + public void interruptSpecialThread(int threadId) { + Map allThread = Thread.getAllStackTraces(); + for (Map.Entry entry : allThread.entrySet()) { + if (entry.getKey().getId() == threadId) { + entry.getKey().interrupt(); + return; + } + } + } + @Override public T[] getInstances(Class klass) { return getInstances0(klass, -1); diff --git a/arthas-vmtool/src/main/java/arthas/VmToolMXBean.java b/arthas-vmtool/src/main/java/arthas/VmToolMXBean.java index f21000115..076a8f697 100644 --- a/arthas-vmtool/src/main/java/arthas/VmToolMXBean.java +++ b/arthas-vmtool/src/main/java/arthas/VmToolMXBean.java @@ -20,6 +20,13 @@ public interface VmToolMXBean { */ public void forceGc(); + /** + * 打断指定线程 + * + * @param threadId 线程ID + */ + void interruptSpecialThread(int threadId); + public T[] getInstances(Class klass); /** diff --git a/arthas-vmtool/src/test/java/arthas/VmToolTest.java b/arthas-vmtool/src/test/java/arthas/VmToolTest.java index 8a573f7e1..b48e76076 100644 --- a/arthas-vmtool/src/test/java/arthas/VmToolTest.java +++ b/arthas-vmtool/src/test/java/arthas/VmToolTest.java @@ -3,9 +3,11 @@ package arthas; import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import org.assertj.core.api.Assertions; +import org.junit.Assert; import org.junit.Test; import com.taobao.arthas.common.VmToolUtils; @@ -182,4 +184,30 @@ public class VmToolTest { Assertions.assertThat(interfaceInstances[0]).isEqualTo(ObjectInstances[0]); } + + @Test + public void test_interrupt_thread() throws InterruptedException { + String threadName = "interruptMe"; + final RuntimeException[] re = new RuntimeException[1]; + Runnable runnable = new Runnable() { + @Override public void run() { + try { + System.out.printf("Thread name is: [%s], thread id is: [%d].\n", Thread.currentThread().getName(),Thread.currentThread().getId()); + TimeUnit.SECONDS.sleep(1000); + } catch (InterruptedException e) { + re[0] = new RuntimeException("interrupted " + Thread.currentThread().getId() + " thread success."); + } + } + }; + Thread interruptMe = new Thread(runnable,threadName); + Thread interruptMe1 = new Thread(runnable,threadName); + + interruptMe.start(); + interruptMe1.start(); + + VmTool tool = initVmTool(); + tool.interruptSpecialThread((int) interruptMe.getId()); + TimeUnit.SECONDS.sleep(5); + Assert.assertEquals(("interrupted " + interruptMe.getId() + " thread success."), re[0].getMessage()); + } } diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/VmToolCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/VmToolCommand.java index c0b3e20b4..548f66acf 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/VmToolCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/VmToolCommand.java @@ -55,6 +55,7 @@ import arthas.VmTool; + " vmtool --action getInstances --className java.lang.String --limit 10\n" + " vmtool --action getInstances --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --className org.springframework.context.ApplicationContext\n" + " vmtool --action forceGc\n" + + " vmtool --action interruptThread -t 1\n" + Constants.WIKI + Constants.WIKI_HOME + "vmtool") //@formatter:on public class VmToolCommand extends AnnotatedCommand { @@ -63,7 +64,7 @@ public class VmToolCommand extends AnnotatedCommand { private VmToolAction action; private String className; private String express; - + private int threadId; private String hashCode = null; private String classLoaderClass; /** @@ -149,8 +150,14 @@ public class VmToolCommand extends AnnotatedCommand { this.express = express; } + @Option(shortName = "t", longName = "threadId", required = false) + @Description("The id of the thread to be interrupted") + public void setThreadId(int threadId) { + this.threadId = threadId; + } + public enum VmToolAction { - getInstances, forceGc + getInstances, forceGc, interruptThread } @Override @@ -225,6 +232,12 @@ public class VmToolCommand extends AnnotatedCommand { vmToolInstance().forceGc(); process.write("\n"); process.end(); + return; + } else if (VmToolAction.interruptThread.equals(action)) { + vmToolInstance().interruptSpecialThread(threadId); + process.write("\n"); + process.end(); + return; }