1

デバッグ中に頻繁に問題に直面しました。

スレッドが例外をスローして終了することがあります。

その問題の理由は、スレッドの呼び出し元/開始者です。

呼び出し元が誤ったパラメーターを送信したか、何かを初期化せずにスレッドを呼び出しました。

特定のスレッドが呼び出された場所を見つけるには、スタック トレースが役に立たないため、少し手間がかかります。

呼び出し元スレッドのスタックトレースを呼び出し先スレッドに追加できたらどうでしょうか。

次の例を考えてみましょう:

public class ThreadTest {
        Thread t = new Thread("executeNonBlocking") {
            @Override public void run() {
                // What would be a good way to 
                // append callerStackTrace to the stack
                // trace of this thread
                System.out.println("inside");
                new Throwable().printStackTrace();
            }
        };

    public void executeNonBlocking() {
        final StackTraceElement[] callerStackTrace = new Throwable().getStackTrace();
        new Throwable().printStackTrace();
        t.start();
    }

    public static void main(String[] args) {
        new ThreadTest().executeNonBlocking();
    }
}

出力

java.lang.Throwable
        at ThreadTest.executeNonBlocking(ThreadTest.java:27)
        at ThreadTest.main(ThreadTest.java:41)
inside
java.lang.Throwable
        at ThreadTest$1.run(ThreadTest.java:34)

望ましい出力

java.lang.Throwable
        at ThreadTest.executeNonBlocking(ThreadTest.java:27)
        at ThreadTest.main(ThreadTest.java:41)
inside
java.lang.Throwable
        at ThreadTest.executeNonBlocking(ThreadTest.java:27)
        at ThreadTest.main(ThreadTest.java:41)
        at ThreadTest$1.run(ThreadTest.java:34)

編集:@peter-lawreyとの議論の後に得られた解決策は次のとおりです

public class StackTraceInheritingThread {

    private final Runnable r;

    private volatile Thread th = null;
    private String title;
    private boolean daemon;

    private InheritedStackTrace ist ;

    private static final ThreadLocal<InheritedStackTrace> tl = new ThreadLocal<InheritedStackTrace>();

    public StackTraceInheritingThread(Runnable r) {
        this.r = r;
    }

    private final class StackTraceInheritingUncaughtExceptionHandler implements  Thread.UncaughtExceptionHandler {

        @Override public void uncaughtException(Thread t, Throwable e) {
            if(ist!=null){ 
                e.addSuppressed(ist);
            }
            e.printStackTrace(System.err);
        }

    }

    public StackTraceInheritingThread setName(String nm){
        this.title = nm;
        return this;
    }

    public StackTraceInheritingThread setDaemon(boolean daemon) {
        this.daemon = daemon;
        return this;
    }

    public void start(){
        if(th!=null){
            throw new IllegalStateException("Already started");
        }

        th = new Thread(new Runnable() {
            @Override public void run() {
                tl.set(ist);
                r.run();
            }
        },title);
        th.setUncaughtExceptionHandler(new StackTraceInheritingUncaughtExceptionHandler());
        if(daemon)th.setDaemon(true);
        ist = new InheritedStackTrace();
        th.start();
    }

    public static Throwable getInheritedStackTrace(){
        return tl.get();
    }

    public static StackTraceInheritingThread make(Runnable r1){
        return new StackTraceInheritingThread(r1);
    }


    private static final class InheritedStackTrace extends Exception {

    }


    public static void main(String[] args) {
        StackTraceInheritingThread.make(new Runnable() {

            @Override
            public void run() {
                System.out.println("heelo");
                throw new RuntimeException();
            }
        }).setName("ExperimentalThread").start();
    }
}
4

1 に答える 1