Lo scenario dovrebbe essere questo:
Una servlet (su cui non ho accesso) crea un oggetto della mia classe e gli invoca un metodo. Io dovrei far partire un altro thread DOPO che questo metodo invocato dalla servlet è terminato.

Vi posto il codice semplicificato delle 2 classi.

Metodo invocato dalla servlet, al termine del quale dev'essere eseguito il thread figlio.
codice:
public void esegui() throws Exception
    {
        try{
            ThreadController controller = new ThreadController();
            Thread thisThread = Thread.currentThread();
            SubThread subThread = new SubThread(controller);
            subThread.start();
            thisThread.sleep(7000);
            System.out.println("Ho finito, avviso il controllore");
            controller.setFinitoThenNotify();
            
        }
        catch(Exception ex)
        {
            System.out.println("Eccezione!");
            ex.printStackTrace();
        }
    }

ThreadFiglio
codice:
 
public class SubThread extends Thread{

    ThreadController controller;
    public SubThread(ThreadController controller)
    {
       
        this.controller=controller;
    }


    public void run()
    {
        try{
            System.out.println("SubThread: Chiedo se ha finito");
            controller.aspettaSeNonFinito();
            System.out.println("SubThread: Mi sono svegliato, vuol dire che ha finito, aspetto ancora qualche secondo...");
                        
            //per sicurezza, dopo che ho ricevuto OK, aspetto ancora 3 secondi, poi proseguo
            sleep(4000);
            System.out.println("SubThread: Ora parto!");
 
            //elaborazione del thread Figlio
        }
        catch(Exception e)
        {
            System.out.println("SubThread: Eccezione!");
        }

    }

}
Questa è la classe dell'oggetto condiviso, che dice se il figlio può partire.
codice:
 
public class ThreadController {

    private boolean finito=false;

    public synchronized void aspettaSeNonFinito() {
        try{
           if(!finito)
            {
                System.out.println("ThreadController: Faccio aspettare perche il thread principale non ha finito");
                wait();
                System.out.println("ThreadController: Sono stato svegliato, il thread principale ha finito");
            }
        }
        catch(Exception e)
        {
            System.out.println("ThreadController: Eccezione!");
        }
        
    }

     public synchronized void setFinitoThenNotify() {
        finito = true;
        System.out.println("ThreadController: Mi è arrivato il permesso di svegliare il thread dormiente, ora lo faccio");
        notifyAll();
    }

}
Ho risolto così, mi pare una buona soluzione. Oltretutto il figlio aspetta qualche secondo prima di partire davvero, per lasciare alla servlet il tempo di elaborare la risposta del mio metodo e fare qualcos'altro.
Il mio problema lo considero risolto, grazie per l'interessamento.