4

我对 java 还很陌生,并且开始使用不同的线程来使用wait()sleep()在我的代码的一部分上使用,并让其他的仍然运行。

对于这个项目,我使用JFrame的是javax.swing.*java.awt.*导入。我想要做的是让其中一个线程(在我的代码中它是主要的起始线程)允许玩家在井字游戏板上选择一个空间,当他们点击它时,它会改变图标,并且然后 AI 将等待 1 秒钟,然后从我创建的第二个线程播放。

不幸的是,每当我调用ait.sleep(1000)ait是我的线程名称)时,两个线程都会等待 1 秒才能完成它们的执行。谁能告诉我为什么休眠一个线程会停止我的整个执行?

4

4 回答 4

15

谁能告诉我为什么休眠一个线程会停止我的整个执行

为了更好地解释您的 Swing GUI 是在其自己的特殊线程上创建的,与其他代码将在其中运行的线程分开main(),这是通过在SwingUtilities.invokeXXX块中创建您的 Swing 组件来完成的(即使您没有这样做,您的 GUI 也将在单线程称为初始线程)。现在,如果您只是简单地调用sleepwhile on Event Dispatch Thread(或就此而言Thread),它将等待调用Thread.sleep完成。现在因为所有 Swing 事件都在 EDT 上处理,我们通过调用暂停它的执行,sleep(..)从而暂停 UI 事件的处理,因此 GUI 被冻结(直到sleep(..)返回)。

你不应该使用Thread.sleep(..)on Event Dispatch Thread(或者任何Threadsleep 会导致不必要的执行阻塞的地方),因为这会导致 UI 看起来冻结。

Thread.sleep(..)是一个很好的示例,它准确地演示了调用GUI 的 EDT引起的这种不需要的行为。

而是使用:

  • 例如摇摆定时器:

    int delay=1000;// wait for second
    
    Timer timer = new Timer(delay, new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            //action that you want performed 
        }
    });
    //timer.setRepeats(false);//the timer should only go off once
    timer.start();
    
  • 摇摆工人

或者如果没有创建/修改 Swing 组件:

  • 定时器任务

  • Thread,然后您将使用Thread.sleep(int milis)(但在任何情况下,这都是 IMO 的最后一个选项)

更新

Swing Timer/SwingWorker仅在 Java 1.6 中添加,TimerTask并且Thread在 Java 1.3 和 JDK 1 中已经存在了更长的时间,因此您甚至可以使用上述两种方法中的任何一种,并将创建/操作 Swing 组件的调用包装成SwingUtilities/EventQueue#invokeXX块;这就是过去做事的方式:P

于 2012-12-28T19:04:48.617 回答
3

Thread.sleep是一种静态方法。通过任何给定的引用来调用它Thread只是一种方便的形式。

结果,任何对的调用sleep实际上都是sleep在调用 current Thread,我怀疑在您的情况下这是事件线程。在事件线程上休眠/阻塞将给出被锁定的外观。

于 2012-12-28T19:28:01.980 回答
2

如果您希望线程休眠,则将该线程ait编码为休眠。一个线程“进入”另一个线程并在低级别推动它的设计从根本上被破坏了。您为每个线程编写代码,因此首先编写它以执行您希望它执行的操作,这样您就无需从外部进入它。

哪个更有意义,是让厨房里的人知道如何做早餐,还是让卧室里的人大喊大叫并指导他们执行做早餐的每一步?当然,你可以告诉他们做早餐。但你绝对不会把每一步都导向低水平。

于 2012-12-28T19:04:14.733 回答
1

Thread.sleep是一种静态方法,它使当前正在执行的线程休眠指定的时间。Java 语法允许您通过变量调用静态方法,但编译器只是使用该变量的编译时类型来确定调用哪个方法,即

Thread ait = null;
ait.sleep(1000); // calls Thread.sleep(1000), causing current thread to sleep.
                 // In particular, does *not* NPE

您还提到wait()- 虽然这是一个实例方法而不是静态方法,但它仍然会导致当前线程进行等待(ait.wait(1000)将导致当前线程等待长达 1 秒或直到另一个线程调用ait.notifyAll())。

在Java 的早期引入了一个Thread.suspend()和它的对应物,以允许一个线程控制另一个线程,但它们很快就被弃用了,因为它们天生容易死锁。resume()如果您希望一个线程“控制”另一个线程,推荐的模式是合作进行,即拥有线程 A 设置和线程 B 读取的某种共享标志,并让 B根据标志让自己进入睡眠状态:

volatile boolean threadBShouldRun = true;

// Thread B
while(true) {
  if(threadBShouldRun) {
    // do some stuff
  } else {
    Thread.sleep(1000);
  }
}

// Thread A
if(someCondition) {
  threadBShouldRun = false;
}

但是使用包中存在的工具通常更容易且不易出错java.util.concurrent。正确地做多线程比表面上看起来要困难得多。

于 2012-12-28T19:29:59.927 回答