是否可以创建钩子线程?



我正在制作一个插件系统,我需要看看插件何时调用Thread.start()是否有类似于Runtime.getRuntime()的方法。addShutdownHook,但挂钩时,线程启动?

Byteman

你可以使用Byteman将你自己的代码注入thread.start()方法。

事实上,在他们的网站上使用Byteman和JVM类的第一个例子是一个展示如何在线程启动时打印到控制台的例子。

Byteman脚本示例来自他们的教程:

RULE trace thread start
CLASS java.lang.Thread
METHOD start()
IF true
DO traceln("*** start for thread: "+ $0.getName())
ENDRULE

参见https://developer.jboss.org/docs/DOC-17213#how_do_i_inject_code_into_jvm_classes了解更多实现细节。


ByteBuddy h1> 果Byteman不是你的东西,有另一个叫做ByteBuddy的库,它可以用来创建一个Java代理,拦截Thread类中的方法。
public class ThreadMonitor {
@RuntimeType
public static Object intercept(@Origin Method method, 
@SuperCall Callable<?> callable) {
System.out.println("A thread start method called");
return callable.call(); //Calling the original start method.
}
}
public class ThreadMonitorAgent {
public static void premain(String arguments, 
Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.nameEndsWith("start"))
.transform((builder, type, classLoader, module) -> 
builder.method(ElementMatchers.any())
.intercept(MethodDelegation.to(ThreadMonitor.class))
).installOn(instrumentation);
}
}

取自ByteBuddy github的示例代码。

您可以枚举线程,但无法同步挂钩创建。

不是正常的方式,但请记住Thread.start是公共的且非final的,因此您可以创建Thread的子类,该子类将在开始之前执行自定义逻辑。

可能起作用的黑魔法解决方案是从运行时删除现有的Thread类(这意味着修改您的JRE/JDK),并将其替换为您的"富集"类。的版本。只要新版本和"正常"版本做同样的事情就可以了。一个(注册本机,调用本机代码),那么应该没问题。

另一个黑魔法的替代方法是查看Thread.start0调用的本机代码并修改它。但是,这意味着要再次使用运行时环境。

最后一个想法是让应用程序始终以类似于调试模式的方式运行,并在到达断点时执行一些操作。这是可行的,因为ide就是这么做的。虽然我们刚刚转移到双进程设计,它需要什么。

我还想知道Java instrumentation package是否可能在这里提供某种替代方案。

嗯。也许有办法。

如果当前上下文有SecurityManager,则检查当前线程是否被允许访问新ThreadThreadGroup

所以…

你可以(理论上)设置一个自定义的SecurityManager,并使用线程组访问检查作为一种方法来"hook"创建新的Thread。但是这只会告诉你一个线程正在被创建,而不是这个线程实际上是什么。因此,这种方法可能足以满足您的需求,也可能不足以满足您的需求。

没有办法钩住Thread.start()调用。


另一种方法是扩展Thread并在子类中创建或启动线程时实现钩子。

您可以在JVM上附加一个调试器,并将断点设置为Thread.start()。或者甚至可以使用JVMTI等编程来实现。然而因此,应用程序不可能对自己的JVM1使用JVMTI…所以这不是传统的"勾"字。

最后,总是可以选择下载OpenJDK,修改Thread类,构建自定义JVM,然后安装它。对于做一些实验来说,这可能没问题,但对于生产应用程序来说,这是一件疯狂的事情。(你不想给自己增加负担……或者你的客户……维护一个永久的OpenJDK分支)


1 -即使在某些情况下是可能的,Thread类也会带来额外的困难。例如,考虑字节码重写之类的事情必须在类加载器加载类之前完成。但是Thread类必须在JVM引导期间加载…

最新更新