5

线程转储包含丰富的信息。例如,如果我怀疑某个动作触发了多次,那么我需要做的就是在每次触发该动作时转储堆栈跟踪,然后调查堆栈是否有错误的动作触发。

在某些情况下,鼓励开发人员放弃顺序执行的概念简单性。例如,Swing 提供 SwingWorker 帮助程序来解决单线程 EDT 的限制。现在,如果我转储堆栈跟踪,它就没有用了,因为该操作是由 SwingWorker 触发的,并且没有关于谁启动了 SwingWorker 任务的信息。

那么,我该如何排除故障呢?是否有“重定向”线程转储以遵循真正原因的巧妙技巧?

4

2 回答 2

2

您可以扩展 SwingWorker 以在创建堆栈时记录堆栈(或在执行时,但您需要创建另一个执行方法,因为它是最终的)。创建原因是相对昂贵的,所以你可能只想在调试时这样做(检查日志级别或类似的)

import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;

public abstract class TracedSwingWorker<T, V> extends SwingWorker<T, V> {

    private final Exception cause;

    public TracedSwingWorker() {
        super();
        this.cause = new Exception("TracedSwingWorker created at:");
    }

    @Override
    protected final T doInBackground() throws Exception {
        try {
            return doWorkInBackground();
        }
        catch(Exception e) {
            if(this.cause != null) {
                Throwable cause = e;
                while(cause.getCause() != null) {
                    cause = cause.getCause();
                }

                cause.initCause(this.cause);
            }

            throw e;
        }
    }

    protected abstract T doWorkInBackground();

    // just for testing
    public static void main(String[] args) {
        new TracedSwingWorker<Void, Void>() {
            @Override
            protected Void doWorkInBackground() {
                throw new IllegalArgumentException("Exception in TracedSwingWorker!");
            }

            @Override
            protected void done() {
                try {
                    get();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }.execute();
    }
}

印刷:

java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Exception in SwingWorker!
        at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
<snip>
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)
    Caused by: java.lang.Exception: SwingWorker created at:
        at TracedSwingWorker.<init>(TracedSwingWorker.java:15)
        at TracedSwingWorker$2.<init>(TracedSwingWorker.java:60)
        at TracedSwingWorker.main(TracedSwingWorker.java:60)
于 2012-08-02T11:16:18.957 回答
0

我可能会告诉你一些你已经知道的事情,但我建议使用ThreadDump

http://www.oracle.com/technetwork/java/javase/tooldescr-136044.html#gbmpn

如果您使用 IDE,那么这很好:

NetBeans http://netbeans.org/kb/docs/java/debug-multithreaded.html

为此,我经常使用 Eclipse。调试器视图具有可视化和跟踪多个线程、打印堆栈和暂停它们的方法。

于 2012-08-02T00:21:08.437 回答