代码之家  ›  专栏  ›  技术社区  ›  Piotr Aleksander Chmielowski

Java定时器的阻塞等效

  •  3
  • Piotr Aleksander Chmielowski  · 技术社区  · 6 年前

    是否有与 java.util.Timer 班级?我正在寻找解决方案,将阻止线程创建计时器。

    以下代码是非阻塞的,并且 "After timer" 立即打印输出。

        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("Hello");
            }
        }, 1000, 1000);
        System.out.println("After timer");
    

    我想实现的是 “计时器后” 只有在计时器已被取消(且之后的计时器已被取消)时才打印消息。

    2 回复  |  直到 6 年前
        1
  •  4
  •   Stephen C    6 年前

    撇开这听起来很奇怪…阻塞线程是浪费…

    我不知道这样做的标准Java API。

    自从 Timer 不是一个 final 类,您可以使用重写扩展类以实现阻塞行为,并使用将(同时)取消阻止任何线程的方法重写取消方法。像这样的:

        public class MyTimer extends Timer {
    
            private final Object lock = new Object();
            private boolean canceled = false;
    
            @Override
            public void schedule(TimerTask task, long delay) {
                synchronize (lock) {
                    super.schedule(task, delay);
                    while (!cancelled) {
                        lock.wait();
                    }
                }
            }
    
            // and more schedule overrides ...
    
            @Override
            public void cancel() {
                synchronize (lock) {
                    super.cancel();
                    canceled = true;
                    lock.notifyAll();
                }
            }
        }
    

    注意 cancel() 类似于标准 Timer::cancel 方法。

    • 已取消计划任务。
    • 如果任务正在执行,则允许其完成。
    • 取消调用不等待任务完成
    • 计时器 已取消,它将不再接受任何任务。

    最后,请注意

    new MyTimer().schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("Hello");
        }
    }, 1000, 1000);
    

    (使用阻塞计划方法)无法解除阻止。这个 MyTimer 必须将实例发布到其他线程,以便该线程可以调用 取消() 关于它。

        2
  •  2
  •   dan.m was user2321368    6 年前

    如果您希望有一个“waitable”timertask,您可以在其中选择等待它被取消,那么下面的类将引入一个 await() 方法,它允许调用方等待计时器任务被取消。

    abstract class WaitableTimerTask extends TimerTask {
    
        private final CountDownLatch countDownLatch = new CountDownLatch(1);
    
        @Override
        public boolean cancel() {
            boolean result = super.cancel();
            countDownLatch.countDown();
            return result;
        }
    
        public void await() throws InterruptedException {
            countDownLatch.await();
        }
    }
    

    你可以用它来做

    public static void main(String[] args) throws InterruptedException {
    
        final WaitableTimerTask waitableTimerTask = new WaitableTimerTask(){
            @Override
            public void run() {
                System.out.println("TimerTask was run.");
            }
        };
        new Timer(true).schedule(waitableTimerTask, 1000, 1000);
        // Some other thread will need to cancel it.
        waitableTimerTask.await();
        System.out.println("TimerTask was canceled.");
    }
    

    也就是说,如果waitableTimertask从未被取消,那么 等待() 将永远阻止。如果任务只计划运行一次,这可能会非常混乱,因为没有人会希望取消它。