我正在尝试学习如何在Java中暂停和恢复线程。我使用的Applet
是implements Runnable
有2个按钮“开始”和“停止”。
public void init(){
th = new Thread(this);
th.start();
btn_increment = new Button("Start");
btn_increment.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
th.notify();
}
});
add(btn_increment);
btn_decrement = new Button("Stop");
btn_decrement.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ev){
try{
th.wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
});
add(btn_decrement);
}
线程的运行方法:
public void run(){
while(true){
repaint();
try{
Thread.sleep(20);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
现在,每当我尝试暂停或恢复线程时,都会引发异常:
Exception in thread "AWT-EventQueue-1" java.lang.IllegalMonitorStateException
笔记:
如果我使用不推荐使用的方法suspend()
和resume()
,则先前的代码可以完美运行,但是文档指出使用notify()
和wait()
而不是同步。我尝试将单词添加synchronized
到actionPerformed
方法中,但仍会引发异常。
有人可以解释 为什么 这不起作用以及如何解决同步问题吗?很少有解释要点真的有多大帮助;)
您误解了wait()
工作原理。调用wait
一个对Thread
对象不会暂停该线程;
相反,它告诉当前正在运行的线程等待其他事件发生。为了解释原因,我需要备份一点并解释synchronized
实际的作用。
输入synchronized
块时,将获得与对象关联的 监视器 。例如,
synchronized(foo) {
获取与对象关联的监视器foo
。
一旦有了监视器,在退出同步块之前,没有其他线程可以获取它。这是wait
和notify
进来。
wait
是Object类上的一种方法,该方法告诉当前正在运行的线程临时释放其持有的监视器。这允许其他线程在上同步foo
。
foo.wait();
该线程将不会继续,直到其他人调用notify
或notifyAll
打开foo
(或线程被中断)。一旦发生这种情况,该线程将尝试重新获取监视器foo
,然后继续。请注意,如果有任何其他线程在等待获取监视器,那么它们可能会首先进入-
无法保证JVM将分发锁的顺序。请注意,wait()
如果没有人致电notify
或,它将永远等待notifyAll
。通常最好使用wait
超时的其他形式。当有人呼叫notify
/
notifyAll
或超时到期时,该版本将被唤醒。
因此,您需要一个线程来进行等待,而另一个线程来进行通知。双方wait
并notify
必须持有他们试图等待或通知的对象监视器;
这就是为什么您看到IllegalMonitorStateException的原因。
一个示例可以帮助您理解:
class RepaintScheduler implements Runnable {
private boolean paused = false;
private final Object LOCK = new Object();
public void run() {
while (true) {
synchronized(LOCK) {
if (paused) {
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
repaint();
}
}
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void pause() {
synchronized(LOCK) {
paused = true;
LOCK.notifyAll();
}
}
public void resume() {
synchronized(LOCK) {
paused = false;
LOCK.notifyAll();
}
}
}
然后,您的Applet代码可以执行以下操作:
public void init() {
RepaintScheduler scheduler = new RepaintScheduler();
// Add listeners that call scheduler.pause and scheduler.resume
btn_increment.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {
scheduler.resume();
}});
btn_decrement.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {
scheduler.pause();
}});
// Now start everything up
Thread t = new Thread(scheduler);
t.start();
}
请注意,Applet类不关心调度程序如何暂停/继续并且没有任何同步块。
因此,这里可能的事件顺序是:
这一切有意义吗?
不需要单独的LOCK变量;我这样做是为了突出您没有在Thread
实例上调用wait /
notify的事实。同样,RepaintScheduler中的逻辑也不理想,而仅仅是说明如何使用等待/通知。
我有个问题。当我在synchronized块中使用时,我有IllegalMonitorStateException。有谁能帮我解决这个问题吗? 我必须这样做,一个线程将发送到第二个线程char,然后这个线程必须等待和第二个线程打印这个char。在第二个线程等待之后,第一个线程再次发送下一个字符 main.java:
我正在学习 处等待(由于< code > synchronized ,它从未进入其代码块)。一旦生产者线程退出它的同步代码块,消费者线程将进入它的。现在,队列是非空的,因为生产者只是在通知之前放了一些东西进去。消费者线程将移除它,调用notify,退出它的块,此时生产者将获得锁,因为它现在已经在生产者函数中的< code>synchronized(lock)行等待。三个问题: > < li> 在我
我试图做到这一点:创建两个不同的线程,一个打印奇数,一个打印偶数。一旦一个线程打印出一个数字,它就必须等待另一个线程,以此类推,这是一个接一个的。 为了实现这一点,我将使用synchronized block以及wait()和notify()。 我正在创建一个类,该类的对象将用于传递给两个线程中的同步块。 -- --- SyncObject作为参数传递给main中的这些不同线程。 但是,此程序会停
问题内容: 似乎该线程都在其他线程调用或在此线程上唤醒。两者之间有什么区别吗? - 编辑 - 我知道一个是通知对象,另一个是中断线程。但是,这两种情况都会导致相同的结果,也就是说,该线程被唤醒,所以我想问的是这两种情况的后果是如何不同的。 问题答案: 当线程在某个监视器上调用notify时,它将唤醒在该监视器上等待的单个线程,但是 哪个 线程被唤醒由调度程序决定。(或者,一个线程可以调用notif
问题内容: 我有很大一部分不是循环的代码,只是发生一次但要花费一些时间的命令列表。我需要它根据更改的布尔值在任何时候暂停或终止此操作。我可以使用其他线程来挂起,恢复和停止此代码,但是不赞成使用这些方法,因此我想避免使用它们。我可以检查每行代码之间的布尔值,但我希望有一个更优雅的解决方案。有什么好方法吗? 问题答案: 自然,使用来处理中断线程的正确方法(在这种情况下,是暂停或停止线程)。它的设计目的
问题内容: 我需要使线程顺序。他们需要按以下顺序启动: 当D完成时,C可以完成,然后B,然后是A。 在这种情况下,最好使用线程或?为什么呢? 我的线程需要启动并打印消息,完成后需要打印。 问题答案: 由于您正在等待“其他”线程完成(即完成执行),因此是更好的选择。 的javadoc 简单地说: 等待该线程死亡。 然后,该机制相对简单: 要说明:您需要参考。因此,指向,指向,指向和不指向任何对象(它