Son*_*ngo 3 java applet multithreading synchronization synchronized
我正在尝试学习如何在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);
}
Run Code Online (Sandbox Code Playgroud)
线程的run方法:
public void run(){
while(true){
repaint();
try{
Thread.sleep(20);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,每当我尝试暂停或恢复该线程时,都会抛出异常:
Exception in thread "AWT-EventQueue-1" java.lang.IllegalMonitorStateException
笔记:
如果我使用弃用的方法suspend(),前面的代码运行完美resume(),但文档指出使用notify()而wait()不是同步.我尝试将该单词添加synchronized到actionPerformed方法中,但它仍然抛出异常.
有人可以解释为什么这不起作用以及如何解决同步问题?几个解释点真的会有很大的帮助;)
Cam*_*ner 10
你误解了它是如何wait()运作的.调用wait一个Thread对象不会暂停该线程; 它反而告诉当前正在运行的线程等待其他事情发生.为了解释原因,我需要稍微补充一下并解释一下究竟synchronized是做什么的.
输入synchronized块时,您将获得与对象关联的监视器.例如,
synchronized(foo) {
Run Code Online (Sandbox Code Playgroud)
获取与该对象关联的监视器foo.
一旦有了监视器,在退出synchronized块之前,没有其他线程可以获取它.这是wait和notify进来.
wait是Object类的一个方法,它告诉当前正在运行的线程暂时释放它所拥有的监视器.这允许其他线程同步foo.
foo.wait();
Run Code Online (Sandbox Code Playgroud)
在其他人调用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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
您的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();
}
Run Code Online (Sandbox Code Playgroud)
请注意,Applet类不关心调度程序如何暂停/恢复,也不关心任何同步块.
所以这里可能的一系列事件是:
这一切都有意义吗?
不需要单独的LOCK变量; 我这样做是为了强调你没有在Thread实例上调用wait/notify这一事实.类似地,RepaintScheduler中的逻辑并不理想,但仅用于说明如何使用wait/notify.