在java中没有通知线程

时间:2014-09-05 22:14:40

标签: java

在这段代码中,两个线程正在运行,我点击两个线程等待第一次点击按钮,当点击按钮第二次我通知两个线程但是没有得到通知请求帮助。

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;
        }
    }

}

1 个答案:

答案 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;
}

我也做了一些其他的改进:

  1. wait()函数可能会遇到虚假的唤醒。它通常应该只在某个其他线程调用notify()时返回,但有时候wait()可能没有特殊原因返回。这是一个虚假的唤醒。为了防止虚假的唤醒,你应该总是在循环中调用wait()并检查你的等待状态。

  2. 我尽可能地缩小了synchronized块的范围。当你在那里时,你会导致其他线程被阻止,所以你需要尽可能快地进入并离开。不要在那里做任何繁重的工作。持有锁时不要调用GUI代码。 不要在同步块内睡觉。