【问题标题】:What thread does sleep method interrupt?sleep方法中断什么线程?
【发布时间】:2017-03-24 02:37:40
【问题描述】:

在阅读 Java doc plus stackoverflow 的答案后没有这个问题,我想到 Thread.sleep() 休眠当前线程。好的。在我的情况下,我如何确定当前线程是什么?

当此代码第一次运行时,它会在执行 main 函数的默认线程中运行。我对吗?所以我们让这个线程休眠一秒钟,让其他线程做他们的事情。

在调用invokeLater() 之后,我们开始从全新的线程运行渲染方法,所以当我们第二次调用Thread.sleep() 时,我们会中断这个新线程,而默认线程正在运行而没有任何中断。我在这里错过了什么吗?

我不明白的最后一件事是,当我测试这段代码时,通过调用Thread.sleep() 它会中断整个 Swing 事物:GUI、事件等。这意味着在我的程序中与 Swing 无关的所有内容都应该运行绝对无缝,但似乎并非如此。

private void render() {
        if (bs == null) {
            createBufferStrategy(3);
            bs = getBufferStrategy();
        }

        g = bs.getDrawGraphics();
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, getWidth(), getHeight());
        onRender(g);
        g.dispose();
        bs.show();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }

        EventQueue.invokeLater(() -> render());
    }

【问题讨论】:

  • Sleep 是一个static 方法,因此它总是会中断当前线程。
  • 它不会打断任何东西。它使当前线程休眠。这是一种静态方法。它不能做任何其他事情。
  • @EJP 是否在我传递给 invokeLater 或 EDT 的新可运行对象中运行渲染方法?
  • Javadoc 中已回答。为什么要在这里浪费时间?
  • @EJP,当我将一个runnable 传递给invokeLater 时,我正在创建另一个线程并使用它的方法run 来调用该渲染方法。这怎么可能?我的意思是,只有一个线程是 EDT。 EDT 以某种方式使用队列,在处理完所有 Swing 内容后,它从可运行对象执行 run 方法,而不创建另一个线程。我只是想了解它在内部是如何工作的。

标签: java multithreading


【解决方案1】:

Thread.sleep() 休眠当前线程 [但是] 我如何确定当前线程是什么?

您误解了“当前线程”的含义。它表示调用该方法的线程。

不要认为Thread.sleep(n) 对线程做任何事情。把它想象成一个什么都不做的方法,然后在几毫秒后返回n

当我将一个runnable 传递给invokeLater 时,我正在创建另一个线程并使用它的方法run 来调用该渲染方法。这怎么可能?

invokeLater(r)r 放入队列中。它还创建 EDT,但前提是 EDT 尚不存在。因此,永远不会有超过一个 EDT。 EDT 最终会从队列中挑选r 并致电r.run()

在您的情况下,r 是由 lambda 表达式 () -> render() 创建的。每次运行render() 函数时,它都会排队一个新的Runnable(),而EDT 几乎会立即再次调用render()

当我测试这段代码时,通过调用 Thread.sleep() 它会中断整个 Swing 的事情

ALL 事件由 EDT 处理。当 EDT 调用您的 render() 方法时,它不能做任何其他事情——它不能处理任何事件——直到 render() 返回。 sleep(1000) 调用确保render() 至少一秒钟内不会返回。那是一整秒,在此期间您的程序将无法响应任何用户输入。

由于 EDT 将或多或少地连续调用您的 render() 函数,这意味着 EDT 几乎所有时间都在休眠,您的程序将大部分时间对用户输入无响应。

【讨论】:

  • 当我将一个runnable 传递给invokeLater 时,我正在创建另一个线程并使用它的方法run 来调用该渲染方法。这怎么可能?我的意思是,只有一个线程是 EDT。 EDT 以某种方式使用队列,在处理完所有 Swing 内容后,它从可运行对象执行 run 方法,而不创建另一个线程。我只是想了解它在内部是如何工作的。
【解决方案2】:

Thread.sleep的静态调用...

使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。该线程不会失去任何监视器的所有权。

(我在粗体下划线)。

如果您在似乎呈现某些 UI 的线程中调用它(或者通常在主运行线程中),您几乎肯定会发现可用性有所下降。

请注意,线程休眠和中断线程的概念是不同的。

这就是为什么你需要在调用Thread.sleep 时捕获InterruptedException,因为线程可能在睡眠时被中断,例如由另一个线程在睡眠线程上调用interrupt

还要注意,线程也可以中断自身,但这显然不会在它同时休眠时发生。

还请注意,在您的情况下,render 通过新的Runnable 递归地将自身的异步调用添加到EventQueue,这似乎很危险。

【讨论】:

  • 渲染方法是在我传递给 invokeLater 的新可运行文件中运行,还是在 EDT 中运行?
  • @Zai render 似乎在新线程中调用 自身。所以,render 的第一次调用会休眠 1 秒,然后在系统事件队列中添加一个新的可运行的调用自身,以此类推......
  • @Zai 事实上,你不是在某处遇到堆栈溢出吗?
  • 这里的一个问题是 OP 和许多 Java 初学者一样,不明白“当前正在执行的线程”是什么意思。当计算机一次不能执行多个线程时,“当前线程”这个名称是有道理的,但现在即使是手机也有多核处理器,“当前线程”不再准确描述正在发生的事情。
【解决方案3】:

我不明白的最后一件事是,当我测试这段代码时,通过调用 Thread.sleep() 它会中断整个 Swing 事物:GUI、事件等。这意味着在我的程序中与 Swing 无关的所有内容应该绝对无缝运行,但似乎不是。

Swing 中的所有 UI 事件都在单个线程中运行。通常它是一个主线程。如果此线程用于某些活动,则整个 UI 将挂起一段时间。为避免挂起,请不要在 UI 控件的侦听器中进行大量计算。

【讨论】:

  • Swing 事件永远不会在main() 线程中处理——至少,在桌面应用程序中不会。它们在事件调度线程 (EDT) 中处理。 EDT 是延迟创建的:在 main() 线程(或任何其他线程)发出需要它的 Swing 调用之前,它不存在。这通常发生在程序第一次将 JFrame 排序到屏幕上时。
【解决方案4】:

只有 Swing 主线程或event dispatch thread 会执行渲染方法。

如果您希望工作线程执行代码,您必须从主线程tell them explicitly

   SwingWorker worker = new SwingWorker<ImageIcon[], Void>() {
    @Override
    public ImageIcon[] doInBackground() {
        final ImageIcon[] innerImgs = new ImageIcon[nimgs];
        for (int i = 0; i < nimgs; i++) {
            innerImgs[i] = loadImage(i+1);
        }
        return innerImgs;
    }

    @Override
    public void done() {
        //Remove the "Loading images" label.
        animator.removeAll();
        loopslot = -1;
        try {
            imgs = get();
        } catch (InterruptedException ignore) {}
        catch (java.util.concurrent.ExecutionException e) {
            String why = null;
            Throwable cause = e.getCause();
            if (cause != null) {
                why = cause.getMessage();
            } else {
                why = e.getMessage();
            }
            System.err.println("Error retrieving file: " + why);
        }
    }
};

例如,您可以跨越多个 SwingWorker,然后休眠主线程。

【讨论】:

    猜你喜欢
    • 2014-03-02
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-01
    相关资源
    最近更新 更多