public static void watch(Thread thread, Runnable task) {
        ObjectUtil.checkNotNull(thread, "thread");
        ObjectUtil.checkNotNull(task, "task");

        if (!thread.isAlive()) {
            throw new IllegalArgumentException("thread must be alive.");
        }

        schedule(thread, task, true);
    }
@Test
    @Timeout(value = 10000, unit = TimeUnit.MILLISECONDS)
    public void testWatch() throws Exception {
        final CountDownLatch latch = new CountDownLatch(1);
        final Thread t = new Thread() {
            @Override
            public void run() {
                for (;;) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ignore) {
                        break;
                    }
                }
            }
        };

        final Runnable task = new Runnable() {
            @Override
            public void run() {
                if (!t.isAlive()) {
                    latch.countDown();
                }
            }
        };

        try {
            ThreadDeathWatcher.watch(t, task);
            fail("must reject to watch a non-alive thread.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        t.start();
        ThreadDeathWatcher.watch(t, task);

        // As long as the thread is alive, the task should not run.
        assertThat(latch.await(750, TimeUnit.MILLISECONDS), is(false));

        // Interrupt the thread to terminate it.
        t.interrupt();

        // The task must be run on termination.
        latch.await();
    }