5

我仍然是 Java 的初学者,所以我对线程和并发的了解不多。但是,由于 java.util.Timer 和 TimerTask 存在问题,我希望能够将 ScheduledThreadPoolExecutor 用作计时器。我对线程的创建非常感兴趣,并且知道我将在几周内了解它们。但是,如果可能的话,有人可以给我一个基本示例,说明如何将我当前使用 util.timer 的迷你测试程序转换为使用 ScheduledThreadPoolExecutor?

我想尽快完成这个例子,所以我没有太多时间来学习线程——不管我多么想。话虽如此,请包括您认为 Java 初学者应该了解的有关 ScheduledThreadPoolExecutor 的任何重要内容。

示例程序

我做了一个简单的小例子来代表我在一个更大的程序中遇到的问题。这个程序应该做的是允许用户按下一个按钮来启动一个计数器。然后,用户必须能够在她/他想要的时候停止和重新启动计数器。在较大的程序中,此计数器保持相等至关重要,因此我使用了 scheduleAtFixRate() 方法。同样重要的是初始延迟始终相同(在本例中为 0)。问题(我相信你会看到)是一旦定时器被取消,它就无法重新启动——我希望 ScheduledThreadPoolExecutor 能解决这个问题。

代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.TimerTask;
import java.util.Timer;

public class Tester extends JFrame {
    JButton push = new JButton("Push");
    static JTextArea textOut = new JTextArea();
    Timer timer = new Timer();
    boolean pushed = false;
    static int i = 1;

    public Tester() {
        super();
        add(push, BorderLayout.NORTH);
        add(textOut);
        push.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!pushed) {
                    timer.scheduleAtFixedRate(new Task(), 0, 1000);
                    pushed = true;
                } else {
                    timer.cancel();
                    pushed = false;
                }
            }
        });
    }

    static class Task extends TimerTask {
        public void run() {
            textOut.setText("" + i++);
        }
    }

    public static void main(String[] args) {
        Tester a = new Tester();
        a.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        a.pack();
        a.setVisible(true);
    }
}

我经常使用这个类进行测试,所以可能会有额外的代码(我想我把它全部删除了)。

4

1 回答 1

23

代替

Timer timer = new Timer();

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

class Task extends TimerTask

class Task implements Runnable

timer.scheduleAtFixedRate(new Task(), 0, 1000);

service.scheduleAtFixedRate(new Task(), 0, 1000, TimeUnit.MILLISECONDS);

顺便说一句,您不应该尝试在另一个线程上更新 GUI。相反,您必须向 Swing GUI 线程添加一个任务来执行该任务

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            textOut.setText("" + i++);
        }
    });
于 2013-01-14T08:50:14.743 回答