使用"通知()" &安培; "等待()"代替"暂停()"和"个人简历()"控制线程 [英] Using "notify()" & "wait()" instead of "suspend()" and "resume()" to control a thread
问题描述
我想了解如何暂停,并在Java中恢复线程。我使用的是 Applet的
的实现Runnable
有2个按钮开始和停止。
I'm trying to learn how to pause and resume a thread in java. I'm using an Applet
that implements Runnable
has 2 buttons "Start" and "Stop".
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);
}
该线程的run方法:
The run method of the thread:
public void run(){
while(true){
repaint();
try{
Thread.sleep(20);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
现在每当我试图暂停或恢复该线程将抛出一个异常:
Now whenever I try to to pause or resume the thread an exception is thrown:
异常螺纹AWT-EventQueue的-1java.lang.IllegalMonitorStateException
注:
在previous code完美地运行,如果我用的是德precated方法暂停()
和简历()
,但文档在使用指出通知()
和等待()
,而不是用同步。我尝试添加同步字
到的actionPerformed
方法,但它仍然抛出异常。
The previous code runs perfectly if I use the deprecated methods suspend()
and resume()
, but the documentation points out at using notify()
and wait()
instead with synchronization. I tried adding the word synchronized
to the actionPerformed
method, but it still throws the exception.
能否有人请解释的为什么这是不工作,如何解决同步问题?很少解释点真的有很大帮助;)
Can someone please explain WHY this isn't working and how to solve the synchronization problem? Few explanation points would really be of much help ;)
推荐答案
您误解了如何等待()
的作品。调用等
在发
对象不会暂停该线程;它,而不是告诉当前运行的线程等待其他事情发生。为了解释为什么,我需要备份了一下,解释一下同步
实际上做。
You have misunderstood how wait()
works. Calling wait
on a Thread
object does not pause that thread; it instead tells the currently running thread to wait for something else to happen. To explain why, I'll need to back up a bit and explain what synchronized
actually does.
当你输入一个同步
阻止你获得的监测的与对象相关联。例如,
When you enter a synchronized
block you obtain the monitor associated with an object. For example,
synchronized(foo) {
获得与对象富
相关联的监视。
一旦你的显示器,没有其他的线程可以得到它,直到你退出synchronized块。这是等
和通知
进来了。
Once you have the monitor, no other threads can obtain it until you exit the synchronized block. This is where wait
and notify
come in.
等
是告诉当前运行的线程暂时释放其持有的显示器Object类的方法。这允许其他线程富
同步。
wait
is a method on the Object class that tells the currently running thread to temporarily release the monitor it holds. This allows other threads to synchronize on foo
.
foo.wait();
这线程将不会恢复,直到别人通话通知
或 notifyAll的
在富
(或者线程被中断)。一旦出现这种情况,该线程将尝试重新获得了富
,然后继续监视。请注意,如果任何其他线程都在等待获得监视器,那么他们可能会在第一次拿到 - 没有订单JVM将手伸出来锁保证。需要注意的是等待()
将永远等待,如果没有人通话通知
或 notifyAll的
。它通常是最好用的其他形式的等
,它接受一个超时。这个版本会醒过来的时候有人叫通知
/ notifyAll的
或当超时已过期。
This thread will not resume until someone else calls notify
or notifyAll
on foo
(or the thread is interrupted). Once that happens, this thread will attempt to re-acquire the monitor for foo
and then continue. Note that if any other threads are waiting to obtain the monitor then they might get in first - there is no guarantee of the order the JVM will hand out locks. Note that wait()
will wait forever if no-one calls notify
or notifyAll
. It's usually best to use the other form of wait
that takes a timeout. That version will wake up when someone calls notify
/notifyAll
or when the timeout has expired.
所以,你需要一个线程做的等待和不同的线程来完成的通知。无论等
和通知
必须持有他们试图等待或通知的对象监视器;这就是为什么你看到的抛出:IllegalMonitorStateException。
So, you need one thread to do the waiting and a different thread to do the notifying. Both wait
and notify
must hold the monitor on the object they are trying to wait on or notify; this is why you are seeing the IllegalMonitorStateException.
一个例子可以帮助你理解:
An example might help you understand:
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 code就可以做到这一点:
Your Applet code can then do this:
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类不关心调度程序如何暂停/简历,没有任何synchronized块。
Note that the Applet class does not care about how the scheduler pauses/resumes and does not have any synchronized blocks.
所以这里的事件可能的顺序是:
So a possible sequence of events here is:
- 线程A开始运行重绘调度。
- 线程A进入睡眠状态20毫秒。
- 线程B(事件调度线程)接收点击一个按钮;来电暂停。
- 线程B获得监视器上的锁。
- 线程B更新'暂停'变量并调用LOCK.notifyAll。
- 没有线程在等待锁所以没有什么有趣的发生。
- 线程B释放在监视器上的锁。
- 线程A被唤醒,通过其循环再次变。
- 线程A获得监视器上的锁。
- 线程A发现它应暂停,所以它调用LOCK.wait。
- 在这一点上线程A暂停,等待有人打电话notifyAll的。线程A释放的锁定显示器。
- 一段时间后,用户点击恢复。
- 线程B调用scheduler.resume。
- 线程B获得监视器上的锁。
- 线程B更新'暂停'变量并调用LOCK.notifyAll。
- 线程A看到'notifyAll的和醒来。它试图获取锁定显示器,但它是由线程B持有这样线程A块。
- 线程B释放在监视器上的锁。
- 线程A获得的监测和进行的。
这是否行得通的?
有不需要一个单独的锁变量;我已经做了,要强调的是,你是不是调用wait /通知在发
实例。同样,RepaintScheduler内部的逻辑是不理想的,但只是为了说明如何等待/通知也可以使用。
Having a separate LOCK variable is not required; I've done that to highlight the fact that you are not calling wait/notify on a Thread
instance. Similarly, the logic inside the RepaintScheduler is not ideal but is just there to illustrate how wait/notify could be used.
这篇关于使用"通知()" &安培; "等待()"代替"暂停()"和"个人简历()"控制线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!