简体   繁体   中英

My timer is stopping at random intervals in java

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Timer;

import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.SWT;


public class GUITest3 {


    //Declare sections of GUI
    private static Shell shell = new Shell();
    CLabel sensorTitleLabel = new CLabel(shell, SWT.SHADOW_OUT);
    CLabel sensorNum_1 = new CLabel(shell, SWT.BORDER | SWT.SHADOW_IN);
    CLabel lblBattery = new CLabel(shell, SWT.SHADOW_OUT);
    CLabel lblLastAlert = new CLabel(shell, SWT.SHADOW_OUT);
    CLabel lblAlert = new CLabel(shell, SWT.SHADOW_OUT);
    CLabel batter_1 = new CLabel(shell, SWT.BORDER | SWT.SHADOW_IN);
    final CLabel lstAlert_1 = new CLabel(shell, SWT.BORDER | SWT.SHADOW_IN);
    CLabel alert_1 = new CLabel(shell, SWT.BORDER | SWT.SHADOW_IN);
    CLabel sensorNum_2 = new CLabel(shell, SWT.BORDER | SWT.SHADOW_IN);
    CLabel battery_2 = new CLabel(shell, SWT.BORDER | SWT.SHADOW_IN);
    CLabel lstAlert_2 = new CLabel(shell, SWT.BORDER | SWT.SHADOW_IN);
    CLabel alert_2 = new CLabel(shell, SWT.BORDER | SWT.SHADOW_IN);


    public GUITest3()
    {
        //Default constructor sets up the values for the GUI
        shell.setSize(450, 300);
        shell.setText("SWT Application");

        sensorTitleLabel.setAlignment(SWT.CENTER);
        sensorTitleLabel.setBounds(10, 10, 100, 21);
        sensorTitleLabel.setText("Sensor Number");

        sensorNum_1.setBounds(10, 37, 100, 21);
        sensorNum_1.setText("");

        lblBattery.setAlignment(SWT.CENTER);
        lblBattery.setText("Battery");
        lblBattery.setBounds(116, 10, 100, 21);

        lblLastAlert.setAlignment(SWT.CENTER);
        lblLastAlert.setText("Last Alert");
        lblLastAlert.setBounds(222, 10, 100, 21);

        lblAlert.setAlignment(SWT.CENTER);
        lblAlert.setText("Alert");
        lblAlert.setBounds(328, 10, 100, 21);

        batter_1.setText("");
        batter_1.setBounds(116, 37, 100, 21);

        lstAlert_1.setText("");
        lstAlert_1.setBounds(222, 37, 100, 21);

        alert_1.setText("");
        alert_1.setBounds(328, 37, 100, 21);

        sensorNum_2.setText("");
        sensorNum_2.setBounds(10, 64, 100, 21);

        battery_2.setText("");
        battery_2.setBounds(116, 64, 100, 21);

        lstAlert_2.setText("");
        lstAlert_2.setBounds(222, 64, 100, 21);

        alert_2.setText("");
        alert_2.setBounds(328, 64, 100, 21);
        synchronized(this)
        {
            //Starts the timer, passing in the GUI
            new AlertTimer(this).start();
        }
    }
    /**
     * Launch the application.
     * @param args
     */
    public static void main(String[] args) {

        try {
            GUITest3 window = new GUITest3();
            window.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Open the window.
     */
    public void open() {
        Display display = Display.getDefault();
        shell.open();
        shell.layout();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    public void setTimerLabel(final String timeLeft)
    {
        //For changing the displayed time
        Display.getDefault().asyncExec(new Runnable() {
            public void run()
            {
                lstAlert_1.setText(timeLeft);
            }
        });
    }




}

class AlertTimer {
    private static final int TIMER_PERIOD = 1000;   //Sounts in one second intervals
    protected static final int MAX_COUNT = 300;     //Max count, a.k.a. five minutes
    private GUITest3 gui;
    private int count = 0;

    public AlertTimer(GUITest3 screenie) {
        gui = screenie;
        String text = (count / 60)+":0"+(count % 60);
        screenie.setTimerLabel(text);
    }

    public void start() {
        new Timer(TIMER_PERIOD, new ActionListener() {
            @Override
            public synchronized void actionPerformed(ActionEvent e) {
                if (count < MAX_COUNT) {
                    count++;
                    String text = "";
                    if((count % 60) > 9)
                    {
                        text = (count / 60)+":"+(count % 60);
                    }
                    else
                        text = (count / 60)+":0"+(count % 60);
                    System.out.println(text);
                    gui.setTimerLabel(text); 
                } else {
                    //((Timer) e.getSource()).stop();
                    Display.getDefault().syncExec(new Runnable() {
                        public void run()
                        {
                            synchronized (gui)
                            {
                                AlertFlash alrt1 = new AlertFlash(gui);
                                Thread flashing = new Thread(alrt1);
                                flashing.start();
                            }
                        }
                    });
                }
            }
        }).start();
    }

}

So, this is a gui that displays a timer and begins counting up, stopping when it hits 5:00 (does some stuff then, but still working on that, I know there are problems with it, but I'm going to keep pottering with that while I'm thinking about this timer). For some reason I can't figure out, the timer will occasionally just stop. I've had the timer stop counting at 4:18, 0:02, 2:13 etc, I spent some time seeing if there was a pattern to it, to see if that would lead me to any conclusions but I can't see a pattern. No error message either, it just stops.

I'm thinking it's something to do with the Thread aspect (where I admit, my knowledge is quite lacking, still getting there), maybe a missing 'Synchronized' or 'volatile' or similar, I've tried adding in and removing the odd 'synchronized'/'volatile' where I thought it made sense, but still same problem.

Have also tried putting the AlertTimer code in a separate class, implementing Runnable and running it through a different Thread, but same thing, the timer stops ticking at random points.

Kinda running out of ideas on what to try, or where I'm going wrong. Hope you guys can help! Thanks for reading.

I haven't used SWT, but I guess in this case it's very similar to Swing or JavaFX.

You should never do this in an update queue. It's meant to be a minor non-blocking operation, otherwise it could just block further updates, and this is what's happenning in your case:

Display.getDefault().syncExec(new Runnable() { // <- try changing it to asyncExec
    public void run()
    {
        synchronized (gui)                     // <-- try removing this
        {
            AlertFlash alrt1 = new AlertFlash(gui);
            Thread flashing = new Thread(alrt1);
            flashing.start();
        }
    }
});

One other possible cause could be syncExec(runnable) which blocks action execution - this should also not happen inside an action. You could try using asyncExec(runnable) to avoid this.

syncExec在任务运行时暂停执行,并且计时器是单个线程,因此如果syncExec需要超过TIMER_PERIOD ms来完成下一次迭代将被延迟。

I had exactly the same problem with javax.swing.Timer . As specified by the author in one comment, you should rewrite the code using java.util.Timer and java.util.TimerTask .

  • Convert the ActionListener to TimerTask
  • Convert the timer.start to timer.scheduleAtFixedRate(timerTask, 1000, 1000); (to count each second after one second)
  • Convert the timer.stop to timerTask.cancel

I end up with something like this :

class MyTimerTask extends TimerTask {
    @Override
    public void run() {
        count++;
    }
}

MyTimerTask timerTask = null;
int count = 0;

public void start() {
    count = 0;
    timerTask = new MyTimerTask();
    timer.scheduleAtFixedRate(timerTask, 1000, 1000);
}

public void stop() {
    if (timerTask != null)
        timerTask.cancel();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM