方法1: Thread.join()
thread.join(): 続行する前に、threadの実行が完了するまで待つ。
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"-a");
}, "thread_1");
Thread thread2 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"-aa");
}, "thread_2");
Thread thread3 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"-aaa");
}, "thread_3");
thread1.start();
thread1.join();
thread2.start();
thread2.join();
thread3.start();
thread3.join();
}
出力結果:
Thread_1-a
Thread_2-aa
Thread_3-aaa
方法2: Thread.join() のバリアント
スレッドクラスを抽出する
public class QueueThread extends Thread {
private Thread preThread;
private String text;
QueueThread(Thread preThread, String str){
this.preThread = preThread;
this.str = text;
}
@Override
public void run() {
try {
if (preThread != null) {
preThread.join();
}
System.out.println(Thread.currentThread().getName() + "-" + text);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
OrderTread thread1 = new OrderTread(null, "a");
OrderTread thread2 = new OrderTread(thread1, "aa");
OrderTread thread3 = new OrderTread(thread2, "aaa");
thread1.start();
thread2.start();
thread3.start();
}
}
出力:
Thread-0-a
Thread-1-aa
Thread-2-aaa
方法3: CountDownLatch
java.util.concurrent.CountDownLatchをの使用し1つのスレッド (または複数のスレッド) を実装し、他のスレッドが完了するまで待ってから実行します。
public static void main(String[] args) throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(2);
System.out.println("スタート");
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "-" + "a");
countDownLatch.countDown();
}).start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "-" + "aa");
countDownLatch.countDown();
}).start();
countDownLatch.await();
System.out.println("終了");
}
出力:
スタート
Thread-0-a
Thread-1-aa
終了
方法4:スレッドプールで実装
単一スレッド プール + シーケンシャル キューにより、シーケンシャルな実行を保証します。 executorService.shutdown() は送信されたタスクを受け入れなくなりますが、キュー内のタスクは引き続き実行されます (shutdownNow()、awaitTermination() も同様)
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 3; i++){
executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "-" + i);
}
});
}
executorService.shutdown();
}
出力:
pool-1-thread-1-0
pool-1-thread-1-1
pool-1-thread-1-2
方法5: CompletableFuture
1. CompletableFuture.runAsync() は future1.thenRun() と連携して順序を保証します 2. runAsync()+thenRun() は戻り値を受け入れることができません。戻り値は、supplyAsync()+thenApply() で指定できます。 3. 出力から、CompletableFuture によって使用されるデフォルトのスレッド プールが ForkJoinPool であることがわかります。 カスタムスレッドプールの受信もサポート
CompletableFuture completableFuture = CompletableFuture.runAsync(() -> { System.out.print(""); }, Executors.newCachedThreadPool());
public static void main(String[] args) throws InterruptedException {
CompletableFuture fu1 = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + "-" + "a");
});
CompletableFuture fu2 = fu1.thenRun(()->{
System.out.println(Thread.currentThread().getName() + "-" + "aa");
});
CompletableFuture fu3 = future2.thenRun(()->{
System.out.println(Thread.currentThread().getName() + "-" + "aaa");
});
}
ソリューション
ForkJoinPool.commonPool-worker-1-a
ForkJoinPool.commonPool-worker-1-aa
main-aaa