Java:mytextarea.setText(“hello”)+ Thread.sleep(1000)=奇怪的结果

我有这样的事情:

for(int i=0; i<5; i++){ mytextarea.setText("hello " + i); try{ Thread.currentThread().sleep(1000); //to give time for users to read } catch(Exception e){} } 

我期待它会在文本区显示“hello 0”,等待1秒,然后显示“hello 1”,然后等待1秒等。

但是发生的事情是不同的,等待5秒钟,然后显示“你好4”。

任何想法?

是的 – 你基本上阻止了UI线程,所以它永远不会实际更新。

睡在UI线程中是一个非常糟糕的主意。

如果你想做这样的事情,你应该使用一个Timer 。 (我假设您正在使用Swing。如果没有,请编辑您的问题以指明您正在使用的UI框架。)

您还应该注意Thread.sleep是一个静态方法。 您正在使用它,就好像它是一个实例方法。 不可否认,你碰巧在当前线程上“打电话”,但你的用法表明你认为:

 Thread t = new Thread(...); t.start(); t.sleep(1000); 

会使线程睡眠。 它不会 – 它会使当前线程hibernate,因为这就是Thread.sleep 总是这样做的。 IMO,Java允许您以这种方式调用静态方法是错误的 – 如果您使用的是Eclipse,则可以选择将此方法设置为警告或错误。

就像Jon Skeet的回答中所解释的那样,你应该使用一个计时器,因为你不能阻止EDT并期望UI更新。 下面是您重写为使用Swing计时器的示例代码段。

 ActionListener action = new ActionListener() { int i = 0; public void actionPerfomed(ActionEvent e) { mytextarea.setText("hello " + i++); } }; new javax.swing.Timer(1000, action).start(); 

有关计时器function的更多信息,请参阅Swing教程中的如何使用Swing Timers 。

当您的代码等待时,不会处理任何事件

http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html

阅读javax.swing.SwingUtilities.invokeAndWait()和invokeLater()的javadoc这可能会有所帮助

编辑:感谢Jon和Samuel将所有想法放在一起:

 public class Swing extends JPanel { JTextField textField; static JTextArea textArea; static int line = 1; public Swing() { super(new BorderLayout()); textArea = new JTextArea(5, 20); add(textArea); } private static void createAndShowGUI() { JFrame frame = new JFrame("TextDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new Swing()); frame.pack(); frame.setVisible(true); ActionListener taskPerformer = new ActionListener() { public void actionPerformed(ActionEvent evt) { textArea.append("Hello " + line++ + "\n"); } }; if (line < 5) { new Timer(1000, taskPerformer).start(); } } public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } } 

另一种不阻止事件调度线程 (EDT)的方法是启动一个新线程:

 Thread thread = new Thread(new Runnable() { @Override public void runt() { for (int i=0; i<5; i++) { mytextarea.setText("hello " + i); try { Thread.sleep(1000); //to give time for users to read } catch (InterruptedException e) { break; // interrupt the for } } } }); thread.start(); 

编辑:
通常,Swing不是线程安全的,也就是说,只有在EDT上才能调用未标记为线程安全的Swing方法。 setText()是线程安全的,所以在上面的代码中没问题。

要在EDT上运行代码,可以使用javax.swing.SwingUtilities(或java.awt.EventQueue)中的invokeAndWait()invokeLater() )。

有关更多详细信息,请参阅: Swing的线程策略