Une technique de jointure de thread est proposée par l'API Java pour l'enchaînement d'unités d'exécution.

La méthode join() permet d'implémenter cette technique. Un thread invoquant cette méthode place le thread courant (Thread.currentThread()) en état d'attente, jusqu'à ce que le thread soit achevé. De cette manière, d'autres threads se lançant après cette instruction s'exécuteront réellement dès que le thread, invoquant la méthode join(), soit effectivement achevé, c'est à dire qu'il ne soit plus considéré comme en activité (!thread.isAlive()).

Thread thread = new Thread();
Thread autreThread = new Thread();
thread.start();
thread.join();
autreThread.start();

L'ordre des instructions doit être respecté car dans le cas contraire, un fonctionnement inattendu se produirait. Le démarrage des threads à enchaîner doit se faire forcément après un appel à la méthode join().

La technique de jointure de threads permet de s'assurer que des threads dépendants entre eux et en particulier de leurs résultats finaux, puissent s'exécuter réellement chacun leur tour afin d'obtenir les résultats souhaités et non des résultats intermédiaires.

L'utilisation de la méthode join() est semblable au fonctionnement d'un unique appel de méthode, dans laquelle les tâches sont exécutées les unes après les autres. Il est, également, possible d'obtenir le même résultat avec une combinaison des méthodes sleep() et isAlive().

Exemple [voir]
public class Jointure implements Runnable {
    private int numThread;
    private int compteur;
    private int temps;
    private int valeur;

    public Jointure(int numThread, int compteur, int temps) {
        this.numThread = numThread;
        this.compteur = compteur;
        this.temps = temps;
        this.valeur = 0;
        System.out.println("Construction du thread  n°" + numThread);
    }
    public void run() {
        int increment = 1;
        while (true) {
            System.out.println("\tThread n°" + numThread 
                             + " : Compteur = " + increment);
            try {
                Thread.sleep(temps);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            valeur++;
            if (increment++ == compteur) {
                System.out.println("Thread n°" + numThread + " achevé !");
                valeur = compteur * numThread;
                break;
            }
        }
    }
    private static void lancerTraitement() {
        try {
          Jointure jointure1 = new Jointure(1, 8, 1500);
          Jointure jointure2 = new Jointure(2, 10, 1000);
          Thread thread1 = new Thread(jointure1);
          thread1.start();
          Thread thread2 = new Thread(jointure2);
          System.out.println("Jointure sur le premier thread...");
          thread1.join();
          System.out.println("Fin du premier thread et démarrage du second...");
          thread2.start();
          System.out.println("Jointure sur le second thread...");
          thread2.join();
          System.out.println("Fin du second thread "
                               + "et continuation du thread courant...");
          System.out.println("\tRésultat final du thread n°1 : " 
                               + jointure1.valeur);
          System.out.println("\tRésultat final du thread n°2 : " 
                               + jointure2.valeur);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        System.out.println("Démarrage de l'application...");

        lancerTraitement();

        System.out.println("Fin de l'application...");
    }
}