线程新手:通过并发将线程一个接一个地加入

时间:2018-12-28 09:30:59

标签: java multithreading executorservice

我想一个接一个地运行线程。 使用Java 8可以替代Marathon吗? 不使用ExecuterService

public class Marathon {

    public static void main(String[] args) throws InterruptedException {

        Runnable task = () -> {
            for (int i = 0; i < 10; i++) {

                System.out.println(Thread.currentThread().getName()+ " is running... " + i);
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                }
            }
        };

        Thread t1 = new Thread(task, "Mary");
        Thread t2 = new Thread(task, "David");
        t1.start();
        t1.join(100);
        t2.start();
    }
}

输出:

Mary is running... 0 
David is running... 0 
Mary is running... 1 
David is running... 1 
...

以下代码无法作为马拉松比赛使用:

public class Marathon2 {

    public static void main(String[] args)
            throws InterruptedException, ExecutionException, TimeoutException {

        ExecutorService service = null;

        Runnable task = () -> {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName()
                            + " is running... " + i);
                }
                TimeUnit.MILLISECONDS.sleep(100);

            } catch (InterruptedException e) {
            }
        };
        try {
            service = Executors.newFixedThreadPool(4);

            Future<?> job1 = service.submit(task);
            job1.get(500, TimeUnit.MILLISECONDS);
            Future<?> job2 = service.submit(task);
        } finally {
            if (service != null)
                service.shutdown();
        }
    }
}

输出:

pool-1-thread-1正在运行... 0

...

pool-1-thread-1正在运行... 9

pool-1-thread-2正在运行... 0

...

pool-1-thread-2正在运行... 9

是否可以使用ExecuterService?

预期:

pool-1-thread-1 is running... 0
pool-1-thread-2 is running... 0
...
pool-1-thread-1 is running... 9
pool-1-thread-2 is running... 9

2 个答案:

答案 0 :(得分:1)

无需处理任何线程或直接与执行器,您可以使用CompletableFuture

 Runnable runnable = () -> System.out.println("hi");
 Runnable runnable1 = () -> System.out.println("there");
 CompletableFuture<Void> all = CompletableFuture.runAsync(runnable).thenRun(runnable1);

 all.whenComplete((x,th) -> {
        System.out.println("both done");
 });

请注意,这将使用公共的ForkJoin池,但是您仍然可以提供自己的池。

答案 1 :(得分:0)

两个类没有做相同的事情。您可以通过仔细比较来自己找到解决方案。首先,您确切知道您的头等舱(马拉松)如何工作吗?特别是,您如何看待以下内容?

t1.join(100);

刚刚开始运行的线程t1刚刚进入一个循环,该循环每200毫秒计数一次。 join(100)调用仅使当前(主)线程等待100毫秒。通过将这一行替换为以下内容,您将获得完全相同的结果:

Thread.sleep(100);

现在,主线程已休眠100毫秒,它将启动线程t2。现在,两个线程并行运行,两个线程每200毫秒输出一条线,第二个线程延迟100毫秒,以使它们均匀地交错。

现在让我们看看您的第二种方法Marathon2。与头等舱的一些区别立即显而易见:

  1. Runnable中的睡眠是在循环外部而不是内部。
  2. Runnable中的睡眠时间仅为100毫秒,而不是200毫秒。
  3. 主线程中的最大等待时间是500毫秒,而不是100毫秒。
  4. Future.get方法导致TimeoutException而不是仅继续。无论如何,我们可以简单地将其替换为睡眠,因为这是头等舱的全部工作。

因此,为了消除差异,我们获得了以下Marathon2类,该类的行为与其他类(Marathon)类似,但具有交错线程:

public class Marathon2 {

    public static void main(String[] args)
            throws InterruptedException, ExecutionException, TimeoutException {

        ExecutorService service = null;

        Runnable task = () -> {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName()
                            + " is running... " + i);
                    TimeUnit.MILLISECONDS.sleep(200);
                }

            } catch (InterruptedException e) {
            }
        };
        try {
            service = Executors.newFixedThreadPool(4);

            Future<?> job1 = service.submit(task);
            TimeUnit.MILLISECONDS.sleep(100);
            Future<?> job2 = service.submit(task);
        } finally {
            if (service != null)
                service.shutdown();
        }
    }
}