Java Thread join Method - Java 147

Java Thread join Method – Java 147

Java Thread join Method

讓目前正在執行的執行緒暫停,直到調用 join 的執行緒結束執行才會繼續執行任務,使用 join 方法,可以將不同執行緒結果整合在一起,與 wait 和 notify 方法一樣, Join Method in Java 是另一種執行緒間的同步機制,本篇增加了範例,並透過單元測試來驗證產出結果。

檔案目錄

./
   +- src
       +- test
       |   +- org
       |       +- ruoxue
       |           +- java_147
       |               +- multithreading
       |                   +- thread
       |                       +- ThreadJoinTest.java   

單元測試

Thread join Java 提供執行緒等待、等待逾時等操作。

join

Thread join Java 建立執行緒 A 與執行緒 B ,每秒印出 1 個數字,執行緒 B 等待執行緒 A 執行結束,才會執行任務,印出數字。

	@Test
	public void join() {
		Thread threadA = new Thread(() -> {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String id = "A";
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			IntStream.range(0, 3).forEach(e -> {
				try {
					System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] " + e);
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			});

			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
		});

		Thread threadB = new Thread(() -> {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String id = "B";
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			try {
				threadA.join();
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}

			assertFalse(threadA.isAlive());
			IntStream.range(0, 3).forEach(e -> {
				try {
					System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] " + e);
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			});
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
		});

		threadA.start();
		threadB.start();

		try {
			assertTrue(threadA.isAlive());
			threadB.join();
			assertFalse(threadA.isAlive());
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
		assertFalse(threadB.isAlive());
	}
2023/02/10 13:42:32 T[11] worker: A ready
2023/02/10 13:42:32 T[12] worker: B ready
2023/02/10 13:42:32 T[11] 0
2023/02/10 13:42:33 T[11] 1
2023/02/10 13:42:34 T[11] 2
2023/02/10 13:42:35 T[11] worker: A finished
2023/02/10 13:42:35 T[12] 0
2023/02/10 13:42:36 T[12] 1
2023/02/10 13:42:37 T[12] 2
2023/02/10 13:42:38 T[12] worker: B finished

joinTimeout

Thread join Java 建立執行緒 A ,每秒印出 1 個數字,主執行緒等待 1 秒後逾時,繼續執行任務,然後結束,數字沒有全部印出。

	@Test
	public void joinTimeout() {
		Thread threadA = new Thread(() -> {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String id = "A";
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			IntStream.range(0, 3).forEach(e -> {
				try {
					System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] " + e);
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			});
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
		});
		threadA.start();

		try {
			threadA.join(1000);
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
		assertTrue(threadA.isAlive());
	}
2023/02/10 13:43:55 T[11] worker: A ready
2023/02/10 13:43:55 T[11] 0

mainJoin

Thread join Java 建立執行緒 A 與執行緒 B ,每秒印出 1 個數字,執行緒 A 、 B 都執行結束後,主執行緒才會結束任務, Java join Thread 可以將不同執行緒結果整合在一起

	@Test
	public void mainJoin() {
		Thread threadA = new Thread(() -> {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String id = "A";
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			IntStream.range(0, 3).forEach(e -> {
				try {
					System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] " + e);
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			});
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
		});

		Thread threadB = new Thread(() -> {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String id = "B";
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			IntStream.range(0, 3).forEach(e -> {
				try {
					System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] " + e);
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			});
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
		});

		threadA.start();
		threadB.start();

		try {
			threadA.join();
			threadB.join();
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
		assertFalse(threadA.isAlive());
		assertFalse(threadB.isAlive());
	}
2023/02/10 13:46:29 T[12] worker: B ready
2023/02/10 13:46:29 T[11] worker: A ready
2023/02/10 13:46:29 T[11] 0
2023/02/10 13:46:29 T[12] 0
2023/02/10 13:46:30 T[11] 1
2023/02/10 13:46:31 T[12] 1
2023/02/10 13:46:31 T[11] 2
2023/02/10 13:46:32 T[11] worker: A finished
2023/02/10 13:46:33 T[12] 2
2023/02/10 13:46:35 T[12] worker: B finished

ThreadJoinTest.java

Java join Thread 新增單元測試,驗證 join Method in Java 是否符合預期。

package org.ruoxue.java_147.multithreading.thread;

import static org.junit.Assert.*;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

import org.junit.Test;

public class ThreadJoinTest {

	@Test
	public void join() {
		Thread threadA = new Thread(() -> {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String id = "A";
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			IntStream.range(0, 3).forEach(e -> {
				try {
					System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] " + e);
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			});

			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
		});

		Thread threadB = new Thread(() -> {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String id = "B";
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			try {
				threadA.join();
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}

			assertFalse(threadA.isAlive());
			IntStream.range(0, 3).forEach(e -> {
				try {
					System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] " + e);
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			});
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
		});

		threadA.start();
		threadB.start();

		try {
			assertTrue(threadA.isAlive());
			threadB.join();
			assertFalse(threadA.isAlive());
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}

		assertFalse(threadB.isAlive());
	}

	@Test
	public void joinTimeout() {
		Thread threadA = new Thread(() -> {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String id = "A";
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			IntStream.range(0, 3).forEach(e -> {
				try {
					System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] " + e);
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			});
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
		});
		threadA.start();

		try {
			threadA.join(1000);
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
		assertTrue(threadA.isAlive());
	}

	@Test
	public void mainJoin() {
		Thread threadA = new Thread(() -> {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String id = "A";
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			IntStream.range(0, 3).forEach(e -> {
				try {
					System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] " + e);
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			});
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
		});

		Thread threadB = new Thread(() -> {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			String id = "B";
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " ready");
			IntStream.range(0, 3).forEach(e -> {
				try {
					System.out.println(sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] " + e);
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
			});
			System.out.println(
					sdf.format(new Date()) + " T[" + Thread.currentThread().getId() + "] worker: " + id + " finished");
		});

		threadA.start();
		threadB.start();

		try {
			threadA.join();
			threadB.join();
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}

		assertFalse(threadA.isAlive());
		assertFalse(threadB.isAlive());
	}
}

心得分享

Java Thread join with Examples 當在執行緒上調用 join 方法時,此執行緒會進入等待狀態,直到引用的執行緒結束任務,才會繼續執行工作,Java join Thread 取決於操作系統的定時,可以輸入 timeout 逾時時間來控制等候,join Method in Java 當等待時間到期時,此執行緒又會繼續執行任務。

發佈留言