在这段代码中,两个线程正在运行,我点击两个线程等待第一次点击按钮,当点击按钮第二次我通知两个线程但是没有得到通知请求帮助。
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
public class Main implements ActionListener {
JButton button = new JButton("Click");
JFrame frame = new JFrame();
boolean wait=false;
Counter c[] = new Counter[2];
public static void main(String arg[]) {
new Main();
}
public Main() {
frame.setLayout(new FlowLayout());
frame.getContentPane().setBackground(Color.BLACK);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
button.addActionListener(this);
frame.add(button);
frame.setVisible(true);
c[0]=new Counter();
c[0].execute();
c[1]=new Counter();
c[1].execute();
}
public class Counter extends SwingWorker<Void, Void> {
JLabel label = new JLabel();
public Counter() {
label.setForeground(Color.WHITE);
frame.add(label);
}
public Void doInBackground() {
synchronized (this) {
for(int i=0; i!=-1; i++) {
if(wait==true)
try {this.wait();} catch(Exception exp) {exp.printStackTrace();}
label.setText(""+i);
try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
}
}
return null;
}
}
public void actionPerformed(ActionEvent clicked) {
if(wait==false)
wait=true;
else if(wait==true) {
synchronized (c) {
c.notifyAll();
}
wait=false;
}
}
}
答案 0 :(得分:1)
您需要等待通知的同一个对象。
notifyAll()
来电已在c
上完成。当您致电this.wait()
时,this
会引用两个计数器c[0]
和c[1]
。这是一个问题,因为c[0]
和c[1]
与数组c
不是同一个对象。
将this
替换为c
。
public Void doInBackground() {
try {
for (int i = 0; i != -1; i++) {
synchronized (c) {
// Check the wait condition in a loop to guard against spurious
// wakeups.
while (wait == true) {
c.wait();
}
}
label.setText("" + i);
Thread.sleep(200);
}
}
catch (InterruptedException exception) {
// Exit the loop if the thread is interrupted.
}
return null;
}
我也做了一些其他的改进:
wait()
函数可能会遇到虚假的唤醒。它通常应该只在某个其他线程调用notify()
时返回,但有时候wait()
可能没有特殊原因返回。这是一个虚假的唤醒。为了防止虚假的唤醒,你应该总是在循环中调用wait()
并检查你的等待状态。
我尽可能地缩小了synchronized
块的范围。当你在那里时,你会导致其他线程被阻止,所以你需要尽可能快地进入并离开。不要在那里做任何繁重的工作。持有锁时不要调用GUI代码。 不要在同步块内睡觉。