Search code examples
javatimercountdown

What is wrong with this timer?


I am doing a timer to countdown fro 90 seconds all the way down to zero, however when i run it, it will run for 1 second and terminate, plz help! Point out what is wrong!

package TestingFile;

import javax.swing.*;
import javax.swing.event.*;

import java.awt.*;
import java.awt.event.*;


public class TestingATimer extends JFrame
{
    private Timer timer;
    public int count = 90;

    public TestingATimer()
    {
        timer = new Timer(1000, new TimerListener());
        timer.start();
    }

    private class TimerListener implements ActionListener
    {
        public void actionPerformed (ActionEvent e)
        {
            if (count != 0)
            {   
            count--;
            System.out.println(count + " seconds elapsed"); 
            }
        }

    }

    public static void main (String [] args)
    {
        new TestingATimer ();
    }
}

Solution

  • The (Swing) Timer is likely using a daemon based thread. This means that once the main method exists, there is nothing keeping the JVM from terminating...

    From the Thread JavaDocs

    When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs:

    • The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.
    • All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

    So there is nothing stopping the JVM from terminating.

    The question is, why are you using a javax.swing.Timer without a GUI? What are you trying to achieve?

    Updated

    If you don't want to use a GUI, you will need to use a java.util.Timer, for example...

    import java.util.Timer;
    import java.util.TimerTask;
    
    public class Clock {
    
        private static Timer timer;
    
        public static void main(String[] args) {
    
            timer = new Timer();
            timer.scheduleAtFixedRate(new TickTask(), 0, 1000);
    
        }
    
        public static class TickTask extends TimerTask {
    
            private boolean started = false;
            private long startTime = 0;
    
            @Override
            public void run() {
                if (!started) {
                    started = true;
                    startTime = System.currentTimeMillis();
                } else {
                    long dif = System.currentTimeMillis() - startTime;
                    long seconds = dif / 1000;
                    System.out.println(seconds);
                    if (seconds >= 90) {
                        timer.cancel();
                    }
                }
            }
    
        }
    
    }
    

    Otherwise you'll need to supply some kind GUI...

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class ClockGUI {
    
        public static void main(String[] args) {
            new ClockGUI();
        }
    
        public ClockGUI() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private Timer timer;
            private JLabel clock;
    
            public TestPane() {
                setLayout(new GridBagLayout());
                clock = new JLabel("...");
                add(clock);
                timer = new Timer(1000, new ActionListener() {
    
                    private boolean started = false;
                    private long startTime = 0;
    
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (!started) {
                            started = true;
                            startTime = System.currentTimeMillis();
                        } else {
                            long dif = System.currentTimeMillis() - startTime;
                            long seconds = dif / 1000;
                            clock.setText(Long.toString(seconds));
                            if (seconds >= 90) {
                                timer.stop();
                            }
                        }
                    }
                });
                timer.start();
            }
    
        }
    
    }