[Java] 讓執行緒不同步

一般來說
多條執行緒會同步執行

例如以下程式碼
開了10個執行緒
藉著 print 追蹤執行順序

public class ThreadTest extends Thread {
    public void run() {
        System.out.println(getName() + " start");
        try {
            Thread.sleep((int) (Math.random() * 10000));
        } catch (InterruptedException e) {
            
        }
        System.out.println(getName() + " end");
    }
}

public class Demo {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread t = new ThreadTest();
            t.start();
    }
}

可以看到開始與結束都是不可控的

如果某些業務需求
必須區分執行的先後順序
有三種解決辦法

一、join()

執行緒啟動後呼叫 join 方法
就會等待此執行緒先完成後
再執行其他動作

public class Demo {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread t = new ThreadTest();
            t.start();
            
            try {
                t.join();
            } catch (InterruptedException e) {

            }
        }
    }
}

二、wait()

呼叫 Object 的 wait 方法
注意必須 synchronized
否則會出 IllegalMonitorStateException

public class Demo {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread t = new ThreadTest();
            t.start();
            
            try {
                synchronized (t) {
                    t.wait();
                }
            } catch (InterruptedException e) {

            }
        }
    }
}

三、CountDownLatch 物件

將 CountDownLatch 傳入執行緒
待全部執行完畢倒數

import java.util.concurrent.CountDownLatch;

public class ThreadTest extends Thread {
    CountDownLatch countDownLatch;
    public ThreadTest(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }
    public void run() {
        System.out.println(getName() + " start");
        try {
            Thread.sleep((int) (Math.random() * 10000));
        } catch (InterruptedException e) {
            
        }
        System.out.println(getName() + " end");
        countDownLatch.countDown();
    }
}

設置計數器
倒數至 0 才會執行其他動作

import java.util.concurrent.CountDownLatch;

public class Demo {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            CountDownLatch countDownLatch = new CountDownLatch(1);
            Thread t = new ThreadTest(countDownLatch);
            t.start();
            
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                
            }
        }
    }
}

結果: