线程新手:并发加入一个又一个线程

Thread Newbie: Joining thread one after another with concurrent

我想运行一个接一个地发帖。 Java 8 有没有其他的马拉松比赛方式? 不使用 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 是 运行ning... 0

...

pool-1-thread-1 是 运行ning... 9

pool-1-thread-2 是 运行ning... 0

...

pool-1-thread-2 是 运行ning... 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

无需处理任何线程或直接执行程序,您可以使用 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 池,但您仍然可以提供自己的池。

两个 class 不是在做同样的事情。您可能可以通过仔细比较它们自己找到解决方案。首先,您是否确切知道您的第一个 class(马拉松)是如何运作的?特别是,您认为以下行的作用是什么?

t1.join(100);

刚刚启动运行的线程t1刚刚进入一个每200毫秒计数一次的循环。 join(100) 调用只会导致当前(主)线程等待 100 毫秒。将该行替换为这一行,您将获得完全相同的结果:

Thread.sleep(100);

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

现在让我们看看您的第二种方法,Marathon2。与第一个 class 的一些差异是显而易见的:

  1. Runnable 中的休眠在循环外,而不是在循环内。
  2. Runnable 中的睡眠只有 100 毫秒,而不是 200。
  3. 主线程中的最长等待时间是 500 毫秒,而不是 100。
  4. Future.get 方法导致 TimeoutException 而不是继续。无论如何,我们可以简单地将此调用替换为睡眠,因为这就是第一个 class 所做的全部。

因此,消除差异,我们得到以下 Marathon2 class,其行为方式与另一个 class(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();
        }
    }
}