繁体   English   中英

Java并行执行多个任务超时

[英]Java timeout multiple tasks in parallel

什么是启动1000个任务池(最多可以并行执行4个任务)并在它们(分别)花费3秒以上时自动使它们超时的最佳实践方法是什么?

尽管我发现ExecutorService似乎很有帮助(请参阅下面的另一篇文章的SSCE),但我看不到如何使并行运行的多个任务有效(因为future.get(3, TimeUnit.SECONDS)正在执行与启动任务的线程相同,因此没有机会并行启动多个任务):

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class Test {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Task());

        try {
            System.out.println("Started..");
            System.out.println(future.get(3, TimeUnit.SECONDS));
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            future.cancel(true);
            System.out.println("Terminated!");
        }

        executor.shutdownNow();
    }
}

class Task implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(4000); // Just to demo a long running task of 4 seconds.
        return "Ready!";
    }
}

谢谢!

如果您必须监视每个任务以在超过超时期限时将其杀死,则可以选择

  1. 任务本身必须跟踪时间并适当退出,或者
  2. 您必须为每个任务创建第二个看门狗线程。 看门狗线程设置了一个计时器并进入睡眠状态,在超时间隔到期后醒来,如果该任务仍在运行,则终止该任务。

这是一个棘手的问题。 这是我想出的:

public class TaskQueue<T> {
    private static final Logger logger =
        Logger.getLogger(TaskQueue.class.getName());

    private final Collection<Callable<T>> tasks;

    private final int maxTasks;

    private int addsPending;

    private final Collection<T> results = new ArrayList<T>();

    private final ScheduledExecutorService executor;

    public TaskQueue() {
        this(4);
    }

    public TaskQueue(int maxSimultaneousTasks) {
        maxTasks = maxSimultaneousTasks;
        tasks = new ArrayDeque<>(maxTasks);
        executor = Executors.newScheduledThreadPool(maxTasks * 3);
    }

    private void addWhenAllowed(Callable<T> task)
    throws InterruptedException,
           ExecutionException {

        synchronized (tasks) {
            while (tasks.size() >= maxTasks) {
                tasks.wait();
            }
            tasks.add(task);

            if (--addsPending <= 0) {
                tasks.notifyAll();
            }
        }

        Future<T> future = executor.submit(task);
        executor.schedule(() -> future.cancel(true), 3, TimeUnit.SECONDS);
        try {
            T result = future.get();
            synchronized (tasks) {
                results.add(result);
            }
        } catch (CancellationException e) {
            logger.log(Level.FINE, "Canceled", e);
        } finally {
            synchronized (tasks) {
                tasks.remove(task);
                if (tasks.isEmpty()) {
                    tasks.notifyAll();
                }
            }
        }
    }

    public void add(Callable<T> task) {
        synchronized (tasks) {
            addsPending++;
        }

        executor.submit(new Callable<Void>() {
            @Override
            public Void call()
            throws InterruptedException,
                   ExecutionException {
                addWhenAllowed(task);
                return null;
            }
        });
    }

    public Collection<T> getAllResults()
    throws InterruptedException {
        synchronized (tasks) {
            while (addsPending > 0 || !tasks.isEmpty()) {
                tasks.wait();
            }
            return new ArrayList<T>(results);
        }
    }

    public void shutdown() {
        executor.shutdown();
    }
}

我怀疑可以使用锁和条件(而不是同步)更干净地完成此操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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