As promised, a code sample showing the behaviour of wait() and notify(). Several of them exist already on the net, but sometimes, if you don't look by yourself, you don't understand. The code is a bit long (90 lines).

package sandbox;
public class TimeOut implements Runnable {
    private boolean forceStop;
    private int timeToRun;
    private boolean finished;

    public TimeOut() {
        forceStop = false;
        finished = false;
    }
    
    public void demo(int p_timeToWait, int p_timeToRun) {
        timeToRun = p_timeToRun;
        Thread t = new Thread(this); 
        forceStop = false;
        finished = false;
        t.start();

        try {
            synchronized(t) {
                trace("Monitor acquired");
                t.wait(p_timeToWait);
                trace("Monitor re-acquired");
            }
        } catch (InterruptedException ie) {
            trace("Interrupted while waiting for time-out");
        }

        if (t.isAlive() && !finished) {
            trace("Time out!");
            forceStop = true;
            try {
                trace("Waiting for effective end of work");
                t.join();
                trace("End of work reached");
            } catch (InterruptedException ie) {
                trace("Interrupted while waiting for effective end of work");
            }
        }
    }

    public void run() {
        trace("Starting to work");
		// détermination du port
        for(int i = 0; i < 10 && !forceStop; ++i) {
            try {
                Thread.sleep(timeToRun / 10);
                trace("Working...");
            } catch (InterruptedException ie) {
                trace("Interrupted");
            }
        }
        
        int remaining = timeToRun - (timeToRun / 10) * 10;
        if(remaining > 0) {
            try {
                Thread.sleep(remaining);
            } catch (InterruptedException ie) {
                trace("Interrupted remaining");
            }
        }
        
        finished = true;

        if(!forceStop) {
            forceStop = false;
            trace("Notifying end of work");
            synchronized (Thread.currentThread()) {
                Thread.currentThread().notify();
            }
        }
        
        trace("End of work");
    }

    private static void trace(String s) {
        System.out.println(System.currentTimeMillis()+": "+s);
    }

    public static void main(String[] argv) {
        TimeOut to = new TimeOut();
        trace("Demo 15, 20");
        to.demo(15, 20);
        trace("===");
        trace("Demo 20, 15");
        to.demo(20, 15);
    }
}

A remark, the test "t.isAlive()" is not sufficient, because there is no guarantee that run() finishes before wait() is released. Here is a sample output:

javaw.exe -classpath . sandbox.TimeOut

1057702792318: Demo 15, 20
1057702792318: Monitor acquired
1057702792318: Starting to work
1057702792318: Working...
1057702792318: Working...
1057702792318: Working...
1057702792328: Working...
1057702792328: Working...
1057702792328: Working...
1057702792328: Monitor re-acquired
1057702792328: Time out!
1057702792328: Waiting for effective end of work
1057702792328: Working...
1057702792328: End of work
1057702792328: End of work reached
1057702792328: ===
1057702792328: Demo 20, 15
1057702792328: Monitor acquired
1057702792328: Starting to work
1057702792338: Working...
1057702792338: Working...
1057702792338: Working...
1057702792338: Working...
1057702792338: Working...
1057702792338: Working...
1057702792338: Working...
1057702792338: Working...
1057702792338: Working...
1057702792338: Working...
1057702792348: Notifying end of work
1057702792348: End of work
1057702792348: Monitor re-acquired

Enjoy!