简体   繁体   中英

How to make main thread wait to complete UncaughtExceptionHandler execution

I have the following mutlithreaded code. I want the LatchCode.doStuff() to wait until UncaughtExceptionHandler handler completes it work, but it wasn't. How could I make the main thread to wait for it. I need to propagate the exception to parent for some project requirement to log the error into DB (should happen at the end of processing). Following is the piece of code.

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>();
}

If AA.doStuff() and BB.doStuff() has loger sleeps, then I could Cont.err is not empty and getting into catch block. But whne sleep time is negligible like 1 ms, then if block in main() failed and program is executing as if there is no exception.

So I need calling thread to wait for UncaughtExceptionHandler completion. Could some one help on this.

Thanks in advance

After making exhaustive search, found the following page. Go through the details on how things work in UEH. https://bugs.openjdk.java.net/browse/JDK-8153487

Excerpt from the above thread for short answer:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM