【问题标题】:How to execute tasks in ExecutorService sequentially?如何顺序执行ExecutorService中的任务?
【发布时间】:2015-11-09 06:29:59
【问题描述】:

我有三个线程连接在一起,即第二个线程在第一个线程死后执行。

这是我的代码:

public class Main {
    public static void main(String args[]) throws Exception {
        final Thread thrdA = new Thread(() -> System.out.println("Message 1"));
        final Thread thrdB = new Thread(() -> System.out.println("Message 2"));
        final Thread thrdC = new Thread(() -> System.out.println("Message 3"));

        thrdA.start();
        thrdA.join();
        thrdB.start();
        thrdB.join();
        thrdC.start();
        thrdC.join();

    }
}

如何使用ExecutorService 而不是三个线程对象来实现此功能?

【问题讨论】:

    标签: java multithreading concurrency


    【解决方案1】:

    如果您想要/需要的是在与主应用线程不同的单个线程中一个接一个地执行一组作业,那么请使用Executors#newSingleThreadExecutor

    ExecutorService es = Executors.newSingleThreadExecutor();
    es.submit(() -> System.out.println("Message 1"));
    es.submit(() -> System.out.println("Message 2"));
    es.submit(() -> System.out.println("Message 3"));
    es.shutdown();
    

    【讨论】:

    • 如果我这样做,那么消息不会按照我启动线程的顺序执行,例如输出应该是“消息 1”,然后是“消息 2”,然后是“消息 3”。它们以随机顺序执行,例如“消息 2”、“消息 3”、“消息 1”。我想说的是我将如何为 executorservice 中的每条消息执行一个可运行文件,以便输出按升序排列“消息 1”,然后是“消息 2”,然后是“消息 3”,而不是随机顺序,例如“消息 2”、“消息 3”、“消息 1”。
    • @RaeesSharif-Aamir 我很困惑。您的问题涉及多个线程,但似乎您一次只想做一件事。
    • @David 没错。 OP 只需要一个线程来执行多个任务,一个接一个。
    • @RaeesSharif-Aamir 由于 OP 接受了这个答案,我相信这个问题的标题是错误的。 (或者答案是,如果只有其中一个线程,加入 所有 线程非常容易。)
    • 不要忘记在关机后等待任务完成:es.awaitTermination(1, TimeUnit.HOURS)。它与join 具有相同的实际目标。
    【解决方案2】:

    您可以使用 SingleThread ExecutorService 和 future.get() 方法来控制线程的顺序执行。

    DummyTask 类

    import java.util.concurrent.Callable;
    
    public class DummyTask implements Callable<Integer>
    {
    
    int taskId;
    
    public DummyTask(int taskId) {
        this.taskId = taskId;
    }
    
    @Override
    public Integer call() throws Exception
    {
        System.out.println("excuting task... Task Id: " + taskId);
        return taskId;
    }
    
    }
    

    顺序执行类

    package com.amit.executorservice;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class SequentialExecution 
    {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
    
        DummyTask task1 = new DummyTask(1);
        DummyTask task2 = new DummyTask(2);
        DummyTask task3 = new DummyTask(3);
        Future<Integer> result = null;
        ExecutorService executor = Executors.newSingleThreadExecutor();
    
        result = executor.submit( task1 );
        // future.get() Waits for the task to complete, and then retrieves its result.
        result.get();
    
        result = executor.submit( task2 );
        // future.get() Waits for the task to complete, and then retrieves its result.
        result.get();
    
        result = executor.submit( task3 );
        // future.get() Waits for the task to complete, and then retrieves its result.
        result.get();
    
        executor.shutdown();
    
    }
    }
    

    输出

    excuting task... Task Id: 1
    excuting task... Task Id: 2
    excuting task... Task Id: 3
    

    输出将始终相同,所有任务将按顺序执行。

    【讨论】:

    • 这里的关键是Executors.newSingleThreadExecutor(),而不是Future的用法。
    【解决方案3】:

    如果您的应用程序中已经使用了线程池,您可以通过零线程代理串行执行器的方式重用它,而无需创建特殊的单线程线程池。 javadoc section of Executor interface 中描述了一种实现,另一种优化实现在我的 Github 存储库 CodeSamples 中进行了描述。

    【讨论】:

      猜你喜欢
      • 2011-01-10
      • 2017-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多