简体   繁体   English

为什么不能使用notifyAll()唤醒等待的线程?

[英]Why can't I use notifyAll() to wake up a waiting thread?

I have a thread class having the following two methods: 我有一个具有以下两个方法的线程类:

public void run()
{
    boolean running=true;
    while(running)
    {
        sendImage();
    }
}

private synchronized void sendImage()
{
        if(!imageready.getFlag())
        { 
            try
            {
                wait();
                System.out.println("woke up!");
            }
            catch(Exception e)
            {
                System.out.println("Exception raises in ImgSender while waiting");
            }

        }
        else
        {
            //send image
        }
}

I also has a GUI part with a mouse click method to open the file chooser window to let user choose file. 我还有一个GUI部分,带有鼠标单击方法,可以打开文件选择器窗口,以允许用户选择文件。 The code 编码

        public void mouseClicked (MouseEvent event) 
        {
           chooser=new JFileChooser();

           int status=chooser.showOpenDialog(null);


           if (status == JFileChooser.APPROVE_OPTION)
           { 
               try
               {
                    prepareImage();
               }
               catch(Exception e)
               {
                   System.out.println("file not opened");
                }
            }
         }

   private synchronized void prepareImage() throws Exception
    {
           System.out.println("File chosen");
           imgFile=chooser.getSelectedFile();  
           image.setImg( ImageIO.read(imgFile) );
           imageready.setFlag(true);
           notifyAll();  
           System.out.println("noticed other threads");
    }

But I can't wake the first thread up using the notifyAll() so that it could send the image. 但是我无法使用notifyAll()唤醒第一个线程,以便它可以发送图像。

As @MadProgrammer mentioned, you are not synchronizing on the same lock. 如@MadProgrammer所述,您没有在同一锁上进行同步。 A lock is, well, not sure how else to describe it. 好吧,不确定是否还有其他描述方法。 It's a lock. 这是一把锁。 To lock and wait in Java, you pick an object to represent the "lock". 要在Java中锁定并等待,请选择一个对象来表示“锁定”。

If 2 threads synchronize on 2 different objects, it's like the first thread saying "I am pumping gas in pump #1, if you need to use it, get in line", then the second thread saying "Hey, let me know when you're done with #2" (when pump 2 is out of service). 如果2个线程在2个不同的对象上同步,则就像第一个线程说“我正在#1泵中抽气,如果需要使用它,请排队”,然后第二个线程说“嘿,让我知道您何时用#2完成(泵2停止运行时)。

If you want the second driver to wait for the first driver to finish pumping, then he needs to declare interest in pump #1, the same pump that is being held by someone else. 如果要第二个驾驶员等待第一个驾驶员完成抽水,则他需要对第一个泵(对其他人持有的同一泵)感兴趣。 Likewise, if you want 2 threads to successfully perform a wait and notify, they need to refer to the same object. 同样,如果您希望2个线程成功执行等待和通知,则它们需要引用相同的对象。

Why this may appear confusing in your situation is that you aren't specifying explicit objects to lock on. 在您的情况下,这可能会使您感到困惑的原因是,您没有指定要锁定的显式对象。 You declared your methods as synchronized , which implicitly uses the instance of the object the method is executing against as the lock resource. 您将方法声明为synchronized ,它隐式地使用该方法针对执行的对象的实例作为锁定资源。

public class LockTest implements Runnable {
    public void synchronized doNothing() {
        try {
            System.out.println("Starting lock...");
            Thread.sleep(5000);
            System.out.println("Releasing lock...");
        }
        catch (InterruptedException e) {
        }
    }

    public static void main(String[] args) {
        LockTest test1 = new LockTest();
        LockTest test2 = new LockTest();
        new Thread(test1).start();
        new Thread(test2).start();
        // Notice from the output that the threads do not block each other.
    }
}

We created 2 instances of LockTest , so they do not block each other since they have completely independent locks. 我们创建了2个LockTest实例,由于它们具有完全独立的锁,因此它们不会彼此阻塞。

public class LockTest implements Runnable {
    private Object thingToLockWith;

    public LockTest(Object thingToLockWith) {
        this.thingToLockWith = thingToLockWith;
    }

    public void doNothing() {
        synchronized (thingToLockWith) {
            try {
                System.out.println("Starting lock...");
                Thread.sleep(5000);
                System.out.println("Releasing lock...");
            }
            catch (InterruptedException e) {
            }
        }
    }

    public static void main(String[] args) {
        Object lock = new Object();

        LockTest test1 = new LockTest(lock);
        LockTest test2 = new LockTest(lock);
        new Thread(test1).start();
        new Thread(test2).start();
        // Notice from the output they block.
    }

See how the output differs. 查看输出如何不同。 The second thread has to wait in line for the first thread. 第二个线程必须排队等待第一个线程。

不要在Swing应用程序中直接使用线程API,而要使用Swing工作程序,只需在需要执行后台任务(例如发送图像且不想阻止GUI线程)时创建一个实例即可

It appears you are waiting on a the thread object and the gui object is doing the notify. 看来您正在等待线程对象,而gui对象正在执行通知。

So when you do notifyAll(); 所以当你做notifyAll(); do not expect that waiting on the thread object to wake up, as that is a completely different lock. 不要期望等待线程对象唤醒,因为那是完全不同的锁。

You can just use a common lock. 您可以只使用普通锁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM