繁体   English   中英

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

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

我有一个具有以下两个方法的线程类:

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

我还有一个GUI部分,带有鼠标单击方法,可以打开文件选择器窗口,以允许用户选择文件。 编码

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

但是我无法使用notifyAll()唤醒第一个线程,以便它可以发送图像。

如@MadProgrammer所述,您没有在同一锁上进行同步。 好吧,不确定是否还有其他描述方法。 这是一把锁。 要在Java中锁定并等待,请选择一个对象来表示“锁定”。

如果2个线程在2个不同的对象上同步,则就像第一个线程说“我正在#1泵中抽气,如果需要使用它,请排队”,然后第二个线程说“嘿,让我知道您何时用#2完成(泵2停止运行时)。

如果要第二个驾驶员等待第一个驾驶员完成抽水,则他需要对第一个泵(对其他人持有的同一泵)感兴趣。 同样,如果您希望2个线程成功执行等待和通知,则它们需要引用相同的对象。

在您的情况下,这可能会使您感到困惑的原因是,您没有指定要锁定的显式对象。 您将方法声明为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.
    }
}

我们创建了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.
    }

查看输出如何不同。 第二个线程必须排队等待第一个线程。

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

看来您正在等待线程对象,而gui对象正在执行通知。

所以当你做notifyAll(); 不要期望等待线程对象唤醒,因为那是完全不同的锁。

您可以只使用普通锁。

暂无
暂无

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

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