我的计时器在java中以随机间隔停止

时间:2013-11-20 16:37:53

标签: java multithreading timer

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();
    }

}

所以,这是一个gui,显示一个计时器并开始计时,当它到达5点时停止(然后做了一些事情,但仍然在努力,我知道它有问题,但我要去在我考虑这个计时器的同时保持对它的陶醉)。 由于某些原因我无法弄清楚,计时器偶尔会停止。我有计时器在4:18,0:02,2:13等停止计数,我花了一些时间看看是否有一个模式,看看是否会导致我得出任何结论,但我不能看一个模式。没有错误信息,只是停止。

我认为这与线程方面有关(我承认,我的知识非常缺乏,仍在那里),可能缺少'同步'或'易变'或类似,我试过添加并删除奇怪的'synchronized'/'volatile'我觉得它有意义,但仍然是同样的问题。

还尝试将AlertTimer代码放在一个单独的类中,实现Runnable并通过不同的Thread运行它,但同样的事情,计时器在随机点停止滴答。

有点想要尝试什么,或者我哪里出错了。希望你们能帮忙!谢谢你的阅读。

3 个答案:

答案 0 :(得分:2)

我没有使用SWT,但我想在这种情况下它与Swing或JavaFX非常相似。

您永远不应该在更新队列中执行此操作。这意味着是一个次要的非阻塞操作,否则它可能会阻止进一步的更新,这就是你的情况:

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();
        }
    }
});

另一个可能的原因可能是syncExec(runnable)阻止了动作执行 - 这也不应该发生在动作中。您可以尝试使用asyncExec(runnable)来避免这种情况。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我与javax.swing.Timer存在完全相同的问题。正如作者在一条评论中所指定的那样,您应该使用java.util.Timerjava.util.TimerTask重写代码。

  • ActionListener转换为TimerTask
  • timer.start转换为timer.scheduleAtFixedRate(timerTask, 1000, 1000);(一秒后计算每秒秒数)
  • timer.stop转换为timerTask.cancel

我最终得到这样的东西:

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();
}