import java.awt.*; import java.applet.Applet; public class ThreadJoinFix extends Applet implements Runnable { Button _startThreadButton; TextField _threadTimeToRun; TextField _threadTimeOut; TextField _timeWaited; int _timeToSleep = 100; // THIS PART CHANGES: // We can't use isAlive() method on // Thread because of RACE CONDITION! boolean _isThreadReallyAlive = false; public void init() { setLayout(new BorderLayout()); _startThreadButton = new Button("Start Running The Thread"); add("Center",_startThreadButton); Panel insidePanel = new Panel(); add("South",insidePanel); insidePanel.setLayout(new GridLayout(3,2)); insidePanel.add(new Label("Time in ms for Thread to run:")); _threadTimeToRun = new TextField("2000"); insidePanel.add(_threadTimeToRun); insidePanel.add(new Label("Time in ms before TimeOut:")); _threadTimeOut = new TextField("3000"); insidePanel.add(_threadTimeOut); insidePanel.add(new Label("Time Join Waited:")); _timeWaited = new TextField(""); insidePanel.add(_timeWaited); } private void startThreadClicked() { Thread t = new Thread(this); int timeOut = Integer.parseInt(_threadTimeOut.getText()); long startTime = System.currentTimeMillis(); _timeWaited.setText(""); _isThreadReallyAlive = true; t.start(); // THIS PART CHANGES: // Instead of t.join() we use // our own routine long base = System.currentTimeMillis(); long delay = 0; synchronized(this) { try { while(_isThreadReallyAlive) { delay = timeOut - (System.currentTimeMillis() - base); if (delay <= 0) break; wait (delay); } } catch (InterruptedException e) {} } // End synchronized block long stopTime = System.currentTimeMillis(); t.stop(); _timeWaited.setText((new Integer((int)(stopTime-startTime))).toString()); } public boolean handleEvent(Event event) { if (event.target == _startThreadButton && event.id == Event.ACTION_EVENT) { startThreadClicked(); return true; } return super.handleEvent(event); } public void run() { int timeForThreadToRun = Integer.parseInt(_threadTimeToRun.getText()); int timesToRun = timeForThreadToRun / _timeToSleep; System.out.println("Times To Run: " + (new Integer(timesToRun)).toString()); for (int i = 0; i < timesToRun; i++) { System.out.println( (new Integer(i * _timeToSleep)).toString()); try { Thread.sleep(_timeToSleep); } catch (InterruptedException e) {} } // THIS PART CHANGES: // We have to notify blocking thread that // we have basically ended // // Sets instance variable to let routine // know the thread is basically about to die. synchronized(this) { _isThreadReallyAlive = false; notifyAll(); } } // End of run() } // end of class