Thread.join()

Jeśli chcemy aby aktualny wątek poczekał na inny wątek zanim ten zakończy swoją robotę można do tego celu wykorzystać metodę Thread.join.

Prosty przykład użycia

public class ThreadJoinExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> System.out.println("do sth"));
        thread.start();
        thread.join();
    }
}

Dzięki wywołaniu w powyższym kodzie metody join mamy pewność, że wątek wywołujący (w tym wypadku metoda main) poczeka na wątek przechowywany w referencji thread. Bez tego nie mamy tej gwarancji (w szczególności gdy wątek wywołujący nie jest wątkiem głównym).

Przypadki użycia

Wykonanie równoległe z punktem spójnym

Jest to sytuacja, w której odpalamy przykładowo dwa wątki które wykonują jakieś zadania równolegle. Ale w pewnym momencie chcemy powiedzmy połączyć rezultaty wykonania obu wątków:

class SumTask implements Runnable {
    private int[] array;
    private int start;
    private int end;
    private int sum;

    public SumTask(int[] array, int start, int end) {
        this.array = array;
        this.start = start;
        this.end = end;
    }

    @Override
    public void run() {
        sum = 0;
        for (int i = start; i < end; i++) {
            sum += array[i];
        }
    }

    public int getSum() {
        return sum;
    }
}


public class ThreadJoinExample {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        SumTask task1 = new SumTask(array, 0, array.length / 2);
        SumTask task2 = new SumTask(array, array.length / 2, array.length);

        Thread thread1 = new Thread(task1);
        Thread thread2 = new Thread(task2);

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        int totalSum = task1.getSum() + task2.getSum();
        System.out.println("Total sum of array: " + totalSum);
    }
}

Testy i asercje

W testach obejmujących wątki należy zazwyczaj poczekać na wszystkie wątki przed wykonaniem asercji:

public void testConcurrentMethod() {
    Thread thread1 = new Thread(() -> System.out.println("Do sth"));
    Thread thread2 = new Thread(() -> System.out.println("Do sth else"));

    thread1.start();
    thread2.start();

    try {
        thread1.join();
        thread2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    assertTrue(someCondition...);
}