多线程计时器无法正常工作

时间:2017-11-03 15:05:13

标签: java multithreading swing timer

再次,请帮助我! 在下面的代码中,我想通过按下按钮并在Label中键入计时器线程来开始。每次按下按钮都应该开始一个新线程并在每个标签上标记它。但不幸的是,为每个标签编写了相同的计时器。你能帮助我们做对吗?如果你能告诉我这个错误,我的意思是什么?

public class TimerThreads implements ActionListener{

    JFrame jFrame = new JFrame();
    JLabel[] labels;
    int second = 0;
    int minute = 0;
    String s = "";
    String m = "";
    int l = 0;


    public TimerThreads(){
        JLabel one = new JLabel();
        JLabel two = new JLabel();
        JLabel three = new JLabel();
        JLabel four = new JLabel();
        labels = new JLabel[]{one, two, three, four};

        jFrame.setLayout(new GridLayout(0, 2, 5, 5));
        jFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JButton start = new JButton("Start");
        start.addActionListener(this);

        JButton stop = new JButton("Stop");
        stop.addActionListener(this);

        jFrame.add(start);
        jFrame.add(stop);
        jFrame.setVisible(true);
        jFrame.pack();
    }

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

    @Override
    public void actionPerformed(ActionEvent e) {
        String select = e.getActionCommand();
        switch(select){
            case "Start":
                jFrame.add(labels[l]);
                jFrame.revalidate();
                jFrame.repaint();
                TimerThread t = new TimerThread(labels[l]);
                t.start();
                l++;
                break;
            case "Stop":
                //
                break;
        }
    }

    class TimerThread extends Thread{
        JLabel jLabel;

        public TimerThread(JLabel jLabel) {
            this.jLabel = jLabel;
        }

        @Override
        public void run() {
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    second++;
                    if(String.valueOf(second).length() == 1){
                        s = "0";
                    }
                    else{
                        s = "";
                    }
                    if(second == 60){
                        second = 0;
                        s = "0";
                        minute++;
                    }

                    if(String.valueOf(minute).length() == 1){
                        m = "0";
                    }
                    jLabel.setText(m + String.valueOf(minute) + ":" + s + String.valueOf(second));
                }
            },0, 1000);
        }
    }
}

1 个答案:

答案 0 :(得分:2)

您的错误的原因在于:

public class TimerThreads implements ActionListener {

    JFrame jFrame = new JFrame();
    JLabel[] labels;

    // ***** these fields below
    int second = 0;     
    int minute = 0;
    String s = "";
    String m = "";
    // ***** these fields above

    int l = 0;

这四个字段是类的实例字段,并由您创建的每个TimerTask实例共享,因此所有字段都将显示相同的确切时间。

解决方案是将这些字段设置为嵌套类的本地字段:

public class TimerThreads implements ActionListener {

    JFrame jFrame = new JFrame();
    JLabel[] labels;
    // int second = 0;
    // int minute = 0;
    // String s = "";
    // String m = "";
    int l = 0;

    public TimerThreads() {
        //.....
    }

    // ....


    class TimerThread extends Thread {
        JLabel jLabel;

        public TimerThread(JLabel jLabel) {
            this.jLabel = jLabel;
        }

        @Override
        public void run() {
            java.util.Timer timer = new java.util.Timer();
            timer.scheduleAtFixedRate(new TimerTask() {

                // ***** add these fields here
                int second = 0;
                int minute = 0;
                String s = "";
                String m = "";

说完这个之后,当你使用Swing Timer或者javax.swing.Timer时,你使用了错误的Timer,一个java.util.Timer,你就会得到有风险的代码。这非常重要,因为后一个Timer与Swing事件模型配合良好,可以防止线程冲突。请查看Swing Timer Tutorial

其他问题:如果用户需要运行4个以上的线程,则使用固定大小的数组会导致索引超出范围的风险。请改用ArrayList。