首页 > 解决方案 > Java8;在一个线程上使用睡眠时间,但有多个可调用对象

问题描述

在标准 java8 中是否可以同时在单个线程上执行多个可调用对象?
即当一个可调用对象休眠时,开始处理其他可调用对象。

我目前的实验不起作用:

    ExecutorService executor = Executors.newSingleThreadExecutor();
    List<Future> fs = new ArrayList<>();
    for (int i = 0; i < 2; i++) {
        final int nr = i;
        fs.add(executor.submit(() -> {
            System.out.println("callable-" + nr + "-start");
            try { Thread.sleep(10_000); } catch (InterruptedException e) { }
            System.out.println("callable-" + nr + "-end");
            return nr;
        }));
    }
    try { executor.awaitTermination(5, TimeUnit.SECONDS); } catch (InterruptedException e) { }

结果是:

callable-0-start
callable-0-end
callable-1-start
callable-1-end

我希望有:

callable-0-start
callable-1-start
callable-0-end
callable-1-end

笔记:

标签: javajava-8concurrency

解决方案


您尝试做的是模拟旧 Java 版本中已弃用的功能。那时可以停止、暂停或恢复Thread. 但是来自的javadoc Thread.stop

这种方法本质上是不安全的。使用 Thread.stop 停止线程会导致它解锁所有已锁定的监视器(这是未经检查的 ThreadDeath 异常沿堆栈传播的自然结果)。如果以前受这些监视器保护的任何对象处于不一致状态,则损坏的对象将对其他线程可见,从而可能导致任意行为。停止的许多用法应该由简单地修改一些变量以指示目标线程应该停止运行的代码替换。目标线程应该定期检查这个变量,如果变量指示它要停止运行,则以有序的方式从它的run方法返回。如果目标线程等待很长时间(例如在条件变量上),则应使用中断方法来中断等待。

如本报告所述,做你想做的事的风险是至关重要的,因此这种行为已被弃用。

我建议,与其试图从外部强制正在运行的线程进入某种停止位置,不如考虑一个允许您正确打包代码段的 ThreadPool API,以便可以从线程,后来又恢复了。例如 create Ticket,这将是一个基本作业,一个线程总是在开始另一个线程之前完成它,一个TicketChain顺序连接票证并存储状态。然后制作一个处理程序的处理程序,一张一张地处理票证。如果当前无法完成票证(例如,因为并非所有数据都存在,或者无法获取某些锁),线程可以跳过它,直到稍后的时间点,当所述条件可能为真时。


推荐阅读