【问题标题】:How to make main thread wait to complete UncaughtExceptionHandler execution如何让主线程等待完成 UncaughtExceptionHandler 执行
【发布时间】:2021-08-10 18:26:43
【问题描述】:

我有以下多线程代码。我希望LatchCode.doStuff() 等到UncaughtExceptionHandler 处理程序完成它的工作,但事实并非如此。我怎么能让主线程等待它。对于某些项目要求,我需要将异常传播给父级,以将错误记录到数据库中(应该在处理结束时发生)。以下是一段代码。

public class LatchExceptionTest {
    public static void main(String[] args) {
        LatchCode l = new LatchCode();
        Cont c = new Cont();
        try {
            l.doStuff(c);
            System.out.println("Main Thread - work completed");
            if(!c.err.isEmpty())
                throw new Exception(c.err.toString());
        } catch (Exception e) {
            System.out.println("trace printing start");
            System.out.println(c.err.toString()); // log errors to DB
            System.out.println("trace printing edn");
        }
    }
}

class LatchCode {
    public void doStuff(final Cont cont) throws RuntimeException, InterruptedException {
        System.out.println("Intermediate class start");
        try {
            Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread th, Throwable ex) {
                    cont.err.add(ex.getMessage());
                }
            };
            Thread aggregatorThread = new Thread(() -> {
                try {
                    if(cont.err.size() > 0)
                        return;
                     System.out.println("AGGREGATOR thread START");
                     Thread.sleep(3000);
                     System.out.println("AGGREGATOR thread END");
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            CyclicBarrier barrier = new CyclicBarrier(2, aggregatorThread);
            AA a = new AA(); 
            BB b = new BB();  
            CountDownLatch latch = new CountDownLatch(2);
            Thread one = new Thread(() -> {
                try {
                    a.doSomething();
                } catch (Exception e) {
                    System.out.println("Exception in 1");
                    //Thread.currentThread().interrupt();
                    throw new RuntimeException(e.toString());
                } finally {
                    try {
                        barrier.await();
                    } catch (Exception e) {
                        System.out.println("Exception in 1 finallt");
                        throw new RuntimeException(e.toString());
                    } finally {
                        latch.countDown();
                    }
                }
            });
            Thread two = new Thread(() -> {
                try {
                   b.doSomething();
                } catch (Exception e) {
                    System.out.println("Exception in 2");
                    Thread.currentThread().interrupt();
                    throw new RuntimeException(e);
                } finally {
                    try {
                        barrier.await();
                    } catch (Exception e) {
                        System.out.println("Exception in 2 finallt");
                        throw new RuntimeException(e);
                    } finally {
                        latch.countDown();
                    }
                }
             });
            one.start();
            two.start();
            one.setUncaughtExceptionHandler(h);
            two.setUncaughtExceptionHandler(h);
            latch.await();
        } catch (Exception e) {
            System.out.println("Exception in caller");
            throw new RuntimeException(e);
        } finally {
            System.out.println("Intermediate class end");
        }
    }
}
class AA {
    public void doSomething() throws Exception {
        try {
            System.out.println("1 start");
            Thread.sleep(1); 
            throw new Exception("In AA");
        } catch (Exception e) {
            System.out.println("Exception in AA");
            throw new Exception(e.toString());
        }
    }
}
class BB {
    public void doSomething() throws Exception {
        try {
            System.out.println("2 start");
            Thread.sleep(1); 
        } catch (Exception e) {
            System.out.println("Exception in BB");
        }
        System.out.println("2 end");
    }
}
class Cont {
    ConcurrentLinkedQueue<String> err = new ConcurrentLinkedQueue<String>();
}

如果AA.doStuff()BB.doStuff() 有记录器睡眠,那么我可以Cont.err 不为空并进入catch 块。但是如果睡眠时间可以忽略不计,比如 1 毫秒,那么如果 main() 中的阻塞失败并且程序正在执行,就好像没有异常一样。

所以我需要调用线程来等待UncaughtExceptionHandler 完成。有人可以帮忙吗?

提前致谢

【问题讨论】:

    标签: java multithreading exception countdownlatch uncaughtexceptionhandler


    【解决方案1】:

    在进行了详尽的搜索后,找到了以下页面。详细了解 UEH 中的工作原理。 https://bugs.openjdk.java.net/browse/JDK-8153487

    摘自上述主题的简短回答:

    There is no guarantee that UncaughtExceptionHandlers have run before awaitTermination returns.
    It is a pool thread that sets the state to TERMINATED, so it cannot wait for all pool threads to terminate!
    It seems unlikely we can make this better. It seems that relying on the UEH in this way is a poor design
    

    【讨论】:

      猜你喜欢
      • 2016-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-14
      • 2020-09-21
      • 2012-07-22
      • 1970-01-01
      • 2011-06-05
      相关资源
      最近更新 更多