我正在尝试调试 SwingWorker 线程中发生的可怕异常。如果我可以命名我的 SwingWorker 线程,那么我可以更好地解释我收到的堆栈跟踪。
似乎无法命名 SwingWorker 线程(是吗?)。我正在寻找任何最佳实践或“技巧”来帮助我正确识别我的工作线程,而不仅仅是在我的代码中添加日志语句。
我正在尝试调试 SwingWorker 线程中发生的可怕异常。如果我可以命名我的 SwingWorker 线程,那么我可以更好地解释我收到的堆栈跟踪。
似乎无法命名 SwingWorker 线程(是吗?)。我正在寻找任何最佳实践或“技巧”来帮助我正确识别我的工作线程,而不仅仅是在我的代码中添加日志语句。
虽然您无权访问 SwingWorker 正在使用的 ThreadFactory,但您可以在 SwingWorker 正在运行的任何类的 run() 或 call() 方法中调用 Thread.currentThread().setName() 。
只需确保在线程实际执行代码时设置了该值
SwingWorker 使用的线程来自 Executors.defaultThreadFactory,这意味着它来自池。因此,如果“MyXYZThread”被系统中另一个未能重命名线程的 SwingWorker 重用,那么命名线程可能会产生误导。
我会扩展 SwingWorker 以包含一个名称并在引发异常时记录该名称。
注意:我宁愿不让调用者负责处理异常,但我没有看到不改变 SwingWorker 合同的方法。
private static abstract class MySwingWorker<X, Y> extends SwingWorker<X, Y>
{
private final String taskName;
public MySwingWorker(String name)
{
this.taskName = name;
}
public String getTaskName() {
return taskName;
}
}
用法:
new MySwingWorker<Object,Object>("my task") {
protected Object doInBackground() {
try {
return someCall();
}
catch(Exception e) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE,
"Exception in " + getTaskName(), e);
throw e;
}
}
}.execute();
您应该能够使用反射来获取线程并调用 setName 。您需要使用 setAccessible 方法来执行此操作,并进行一些挖掘以找到您需要访问的变量的名称。
我不喜欢这种方法,但它可能和其他任何方式一样“hacky”......
最佳实践是使用已经提到的 Thread.currentThread().setName(String)。
一个“技巧”是为 SwingWorkers 设置 ThreadFactory:
sun.awt.AppContext context = sun.awt.AppContext.getAppContext();
int maxWorkers = 10;
ThreadFactory factory = ...
ExecutorService executor = Executors.newFixedThreadPool(maxWorkers, factory);
context.put(SwingWorker.class, executor);
这使用了 sun.awt 包中的一个类,所以你已经被警告过了。