import java.awt.*; import java.util.*; import java.text.*; public class ClockComp extends Component { // Using a variation on the "Self-Running Object" // technique from Chapter 11 of "Java Thread Programming". // See that chapter of the book for more on internal threads private volatile String timeStr; private volatile boolean noStopRequested; private Thread internalThread; private DateFormat df; private Dimension prefSize; private Font font; public ClockComp() { prefSize = new Dimension(200, 40); font = new Font("Monospaced", Font.BOLD, 14); df = DateFormat.getTimeInstance(DateFormat.LONG); updateTime(); } public Dimension getPreferredSize() { return prefSize; } public void paint(Graphics g) { g.setFont(font); g.setColor(Color.blue); g.drawString(timeStr, 0, 20); } private void updateTime() { timeStr = df.format( new Date(System.currentTimeMillis())); } private void runWork() { try { while ( noStopRequested ) { updateTime(); repaint(); Thread.sleep(300); } timeStr = "STOPPED - by flag"; } catch ( InterruptedException x ) { timeStr = "STOPPED - by InterruptedException"; } finally { repaint(); System.out.println("clock is stopped"); } } public synchronized void start() { if ( ( internalThread != null ) && ( internalThread.isAlive() == true ) ) { // running already, ignore System.out.println( "clock is already running --ignoring start"); return; } noStopRequested = true; Runnable r = new Runnable() { public void run() { runWork(); } }; internalThread = new Thread(r, "clock"); internalThread.start(); System.out.println("clock started"); } public synchronized void interruptOnly() { if ( ( internalThread != null ) && ( internalThread.isAlive() == true ) ) { internalThread.interrupt(); System.out.println( "clock received interrupt only"); } } public synchronized void stopRequest() { if ( noStopRequested ) { noStopRequested = false; internalThread.interrupt(); System.out.println( "clock received stop request"); } } }