Thread.sleep 是如何真正工作的?

Posted

技术标签:

【中文标题】Thread.sleep 是如何真正工作的?【英文标题】:How does Thread.sleep really work? 【发布时间】:2013-03-13 17:05:08 【问题描述】:

我编写了一个程序,不时设置按钮的setEnableThread.sleep() 在另一个类中。代码如下:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Try extends JFrame implements ActionListener
JButton n1 = new JButton("1");
JButton n2 = new JButton("2");
JButton n3 = new JButton("3");
JButton show = new JButton("Show");


show.addActionListener(this);
n1.setEnabled(false);
n2.setEnabled(false);
n3.setEnabled(false);



public Try()
  super("Try");
  setVisible(true);
  setSize(500, 200);
  setLayout(new GridLayout(1, 4));
  add(n1);
  add(n2);
  add(n3);
  add(show);
  

public void actionPerformed(ActionEvent a) 
Object clicked = a.getSource();
if(show == clicked)
new EasyLevel1().start();



  class EasyLevel1 extends Thread 
    public void run()       
        try 
            n1.setEnabled(true);
            Thread.sleep(1000);
            n1.setEnabled(false);
            n2.setEnabled(true);
            Thread.sleep(1000);
            n2.setEnabled(false);
            n3.setEnabled(true);
            Thread.sleep(1000);
            n3.setEnabled(false);    
         catch (InterruptedException e)
        
        
      

    public static void main(String[] args)
      Try frame = new Try();
      frame.setVisible(true);
    
    

但是,当我把它放在课堂上的actionListener 上时:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Try extends JFrame implements ActionListener
JButton n1 = new JButton("1");
JButton n2 = new JButton("2");
JButton n3 = new JButton("3");
JButton show = new JButton("Show");


show.addActionListener(this);
n1.setEnabled(false);
n2.setEnabled(false);
n3.setEnabled(false);



public Try()
  super("Try");
  setVisible(true);
  setSize(500, 200);
  setLayout(new GridLayout(1, 4));
  add(n1);
  add(n2);
  add(n3);
  add(show);
  

public void actionPerformed(ActionEvent a) 
Object clicked = a.getSource();
if(show == clicked)
            try n1.setEnabled(true);
            Thread.sleep(1000);
            n1.setEnabled(false);
            n2.setEnabled(true);
            Thread.sleep(1000);
            n2.setEnabled(false);
            n3.setEnabled(true);
            Thread.sleep(1000);
            n3.setEnabled(false);
             catch (InterruptedException e)



public static void main(String[] args)
  Try frame = new Try();
  frame.setVisible(true);


它冻结了我的整个程序,基于该示例,我了解到应该在另一个线程中运行线程睡眠以阻止当前类冻结。但我预计新的 thread.sleep 仍会冻结其操作,就像它仍会执行上面的代码一样,但按钮将响应,因为它位于另一个线程中。但令人惊讶的是,它完成了我想要它做的事情,它并没有像第一个程序那样立即将所有内容都设置为禁用。

【问题讨论】:

【参考方案1】:

Thread.sleep() 使当前线程暂停。您在 actionPerformed 中运行它,即在 Swing 事件中。所有 Swing 操作都在单个线程(EDT)中完成。当您使用 Thread.sleep() 暂停它时,Swing 无法处理任何其他事件,因为您还没有从 actionPerformed 侦听器返回。因此,GUI 冻结(不是完整的应用程序,只是 GUI)。

因此,一般来说,在 Swing 事件中执行长时间运行的操作是不好的做法。对于您正在尝试做的事情,最好的选择是使用 Swing 计时器。

【讨论】:

【参考方案2】:

发生的情况是,在第二个示例中,Thread.sleep 阻止了EDT,因此不会发生进一步的 UI 更新。相反,在第一个示例中,您在单独的Thread 中调用sleep,因此不会发生“冻结”。对于此类任务,首选使用Swing Timers。

【讨论】:

没问题,看看Swing Timers :) 是的,虽然我选择了 thread.sleep 因为它对我来说更容易,但我目前正在研究你给我的链接以帮助我理解它们。再次感谢【参考方案3】:

Thread.sleep 将导致执行调用的线程休眠指定的时间(或直到线程被中断)。当您在 actionPerformed 方法中调用它时,它会导致 UI 线程休眠。这就是你的程序被锁定的原因。

您应该启动一个单独的线程,该线程将逐步执行您想要在其间睡觉时进行的各种调用。或者(我认为更好)你可以使用Swing timers 来做你想做的事。

【讨论】:

谢谢它在我的脑海中清晰了很多,所以它真的在第二个例子中做我想要的,但是,当线程睡觉时,它也让我的 gui 代码睡觉,所以它“冻结,因为我的 gui 也是睡觉”并在睡眠后变得有反应,因为它不再睡觉。是这样吗? @JerlyTuazon - 没错。如果您使用摇摆计时器来安排各种 setEnabled 调用,您的 gui 将不会锁定。 我有一个问题,但它与“冻结”无关,但它涉及 thread.sleep。为什么thread.sleep总是有InterruptedException问题?我的意思是他们已经将其解释为睡眠受到干扰或其他原因。但是我尝试只留下 1 行由线程及其 Thread.sleep 执行,但它仍然显示 InterruptedException,据我所知,我的 thread.sleep 没有过早关闭或受到干扰? @JerlyTuazon - 有时,在多线程应用程序中,您希望一个线程向另一个线程发出信号,表明它应该停止正在执行的操作。信令线程可以调用另一个线程的interrupt() 方法来做到这一点。应写入另一个线程以检查其中断标志(使用isInterrupted())。但是,在它睡觉的时候,它显然不能那样做。但是当调用休眠线程的interrupt() 方法时,sleep() 调用会以InterruptedException 过早退出。这不是一个“问题”——它是一个特性:你刚刚被告知(被程序中的另一个线程)退出。 @JerlyTuazon 在您的特定应用程序中使用这种“中断功能”的一种方法是处理在(当前线程的)级联按钮工作期间用户再次单击“显示”的情况。如果您希望级联“重置”,中断当前线程的工作可能是有意义的,以便您可以在新线程中重新启动它。当然,这更像是一种概念性思维练习;当您迁移到 Swing Timers 时,我相信会有一个计时器停止功能。

以上是关于Thread.sleep 是如何真正工作的?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 newman 中设置 setTimeout/Thread.sleep

如何修复调用 Thread.sleep() 时未处理异常的编译错误?

如何在 NetBeans SWING 中的循环中使用 Thread.sleep?

如何在 C# 中重新启动任务?或如何重新启动 Thread.Sleep()?

使用 Thread.Sleep 等待的替代方法

Thread.sleep() 不工作。被跳过的操作