使用睡眠()为单个线程
我相当新的Java,并开始进入使用不同的线程,以便对我的代码的一部分使用wait()
或sleep()
,并让其他人仍然运行。
对于这个项目,我正在使用带有javax.swing.*
和java.awt.*
JFrame
导入。 我想要做的是有一个线程(在我的代码中,它是主要的起始线程)允许玩家在井字棋板上select一个空间,当他们点击它时,它会改变图标,那么AI会等待1秒,然后再从我创build的第二个线程回放。
不幸的是,每当我调用ait.sleep(1000)
( ait
是我的线程名)时,两个线程在完成执行之前等待1秒钟。 谁能告诉我为什么睡一个线程是停止我的整个执行?
谁能告诉我为什么睡一个线程是停止我的整个执行
为了更好地解释你的Swing GUI是在它自己的特殊线程上创build的,它独立于main()
和其他代码的运行,这是通过在SwingUtilities.invokeXXX
块中创buildSwing组件完成的(即使你没有这样做GUI将在称为初始线程的单个线程上运行)。 现在,如果你只是在Event Dispatch Thread
(或者在同一个Thread
)调用sleep
,它将等待Thread.sleep
的调用完成。 现在因为所有的Swing事件都是在EDT上处理的,所以我们通过调用sleep(..)
暂停它的执行,从而暂停处理UI事件,因此GUI被冻结(直到sleep(..)
返回)。
你不应该使用Thread.sleep(..)
在Event Dispatch Thread
(或任何Thread
睡眠会引起不必要的执行阻塞),因为这将导致UI似乎冻结。
下面是一个很好的例子,它演示了在EDT的EDT上调用Thread.sleep(..)
导致的不需要的行为。
而是使用:
-
Swing Timer例如:
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();
-
摇摆工人
或者如果没有创build/修改Swing组件:
-
的TimerTask
-
线程 ,你会然后使用
Thread.sleep(int milis)
(但是这是最后一个选项在任何情况下国际海事组织)
UPDATE
Swing Timer
/ SwingWorker
只是在Java 1.6中添加的,然而, TimerTask
和Thread
已经有了更多的正弦Java 1.3和JDK 1,所以你甚至可以使用上述两种方法中的任何一种,并且可以创build/操作Swing组件在SwingUtilities/EventQueue#invokeXX
块; 多数民众赞成曾经的做法:P
Thread.sleep
是一个静态方法。 通过任何给定的Thread
引用它的调用只是一种方便的forms。
因此,任何sleep
调用都是在当前Thread
上调用sleep
,我怀疑这是您的情况下的事件线程。 在事件线程上的睡眠/阻塞将会出现被锁住的现象。
如果你想让ait
线程进入睡眠状态,那么ait
这个线程编码到睡眠状态。 一个线程“进入”另一个线程并将其推到低位的devise从根本上被打破了。 你为每一个线程编写代码,所以编写它来做你想做的事情,所以你不会从外面伸手去做。
哪一个更有意义,让厨房里的人知道如何做早餐或卧室里的人喊叫,指导他们去做早餐的每一步? 当然,你可以告诉他们做早餐。 但是你绝对不要把每个步骤都指向低级别。
Thread.sleep
是一个静态方法,它导致当前正在执行的线程在指定的时间内hibernate。 Java语法允许你通过一个variables来调用一个静态方法,但是编译器只是使用该variables的编译时types来决定调用哪个方法,即
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()
)。
有一个Thread.suspend()
及其对应的resume()
是在Java早期引入的,它允许一个线程去控制另一个线程,但是由于它们本身就是死锁的,所以很快就被弃用了。 如果你想要一个线程来“控制”另一个线程,推荐的模式是合作执行,也就是说有一些共享的标志,线程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
包中的工具通常更容易,也更不容易出错。 做multithreading的权利比表面上看起来要困难得多。