我对java很新,并开始使用不同的线程,以便在我的代码的一部分上使用wait()
或sleep()
并让其他代码仍然运行。
对于此项目,我使用JFrame
和javax.swing.*
导入java.awt.*
。我想要做的是让其中一个线程(在我的代码中它是主要的,起始线程)允许玩家在tic tac toe board上选择一个空间,当他们点击它时,它将改变图标,并且然后AI将等待1秒钟,然后从我创建的第二个线程回放。
不幸的是,每当我调用ait.sleep(1000)
(ait
是我的线程名称)时,两个线程都会在完成执行之前等待1秒。谁能告诉我为什么睡一个线程会阻止我的整个执行?
答案 0 :(得分:14)
任何人都可以告诉我为什么睡一个线程会阻止我的整个过程 执行
更好地解释您的Swing GUI是在其自己的特殊线程上创建的,与<{1}}和其他代码将运行的特殊线程分开,这是通过在{中创建Swing组件来完成的。 {1}}阻止(即使你没有这样做,你的GUI将在一个名为initial thread的线程上运行。现在,如果您只是在main()
上呼叫SwingUtilities.invokeXXX
(或者在同一sleep
上就此问题),它将等待Event Dispatch Thread
的呼叫完成。现在因为在EDT上处理了所有Swing事件,我们通过调用Thread
暂停执行,从而暂停处理UI事件,因此GUI被冻结(直到Thread.sleep
返回)。
你不应该在Event Dispatch Thread
上使用sleep(..)
(或任何sleep(..)
睡眠会阻止不必要的执行阻止),因为这会导致UI看起来被冻结。
Here是一个很好的例子,它准确地证明了在GUI的EDT上调用Thread.sleep(..)
引起的这种不必要的行为。
而是使用:
Swing Timer例如:
Thread
或者如果没有创建/修改Swing组件:
<强>更新强>
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();
/ Thread.sleep(int milis)
仅在Java 1.6中添加,但是,Swing Timer
和SwingWorker
已经存在了很长的正弦Java 1.3和JDK 1,因此你甚至可以使用上述两种方法中的任何一种,并在TimerTask
块中包装创建/操作Swing组件的调用;这就是以往的方式:P
答案 1 :(得分:3)
Thread.sleep
是一种静态方法。通过任何给定Thread
的引用来调用它只是一种方便的形式。
因此,sleep
的任何调用实际上都在当前sleep
上调用Thread
,我怀疑这是您的案例中的事件线程。在事件线程上进行休眠/阻塞会使您看起来已被锁定。
答案 2 :(得分:1)
如果您希望ait
线程休眠,则将该线程编码为休眠状态。一个线程“进入”另一个线程并将其推向低水平的设计从根本上被打破。你为每个线程编写代码,所以写它是为了做你想做的事情,所以你不需要从外面进入它。
更有意义的是,厨房里的人知道如何煮早餐或者卧室里的人大叫并指导他们完成每个早餐的步骤?当然,你可以告诉他们做早餐。但你肯定不会将每一步都指向低级别。
答案 3 :(得分: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
包中存在的工具通常更容易且更不容易出错。正确地执行多线程比在表面上看起来要困难得多。