Java并行执行多个任务

时间:2016-05-23 20:03:37

标签: java multithreading executorservice

启动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!";
    }
}

谢谢!

2 个答案:

答案 0 :(得分:0)

如果必须监视每个任务以在超过超时期限时将其终止,则

  1. 任务本身必须跟踪时间并适当退出,或者
  2. 您必须为每个任务创建第二个监视程序线程。监视程序线程设置计时器并休眠,在超时间隔到期后唤醒,然后在任务仍在运行时终止该任务。

答案 1 :(得分:-1)

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

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

我怀疑使用锁定和条件而不是同步可以更干净地完成。