为什么我不能使用 notifyAll() 来唤醒等待线程?
Why can't I use notifyAll() to wake up a waiting thread?
我有一个线程 class 具有以下两种方法:
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 部分,使用鼠标单击方法打开文件选择器 window 让用户选择文件。代码
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() 唤醒第一个线程,以便它可以发送图像。
不要在 Swing 应用程序中直接使用线程 API,而是使用 Swing workers,当您需要执行后台任务时,只需创建线程的实例,例如发送图像,而您不需要阻止 GUI 线程
看来您正在等待线程对象,而 gui 对象正在执行通知。
所以当你这样做时notifyAll();
不要指望等待线程对象被唤醒,因为那是一个完全不同的锁。
您可以使用普通锁。
如@MadProgrammer 所述,您没有在同一个锁上进行同步。锁,好吧,不知道还能怎么描述它。这是一把锁。要在 Java 中锁定并等待,您可以选择一个 object 来表示 "lock"。
如果 2 个线程在 2 个不同的 object 上同步,就像第一个线程说 "I am pumping gas in pump #1, if you need to use it, get in line",然后第二个线程说 "Hey, let me know when you're done with #2"(当泵 2 停止服务时) .
如果您希望第二个 driver 等待第一个 driver 完成泵送,那么他需要声明对泵 #1 的兴趣,与其他人持有的同一个泵.同样,如果你想让2个线程成功执行等待和通知,他们需要引用相同的object.
为什么这在您的情况下可能显得令人困惑,因为您没有指定 explicit objects 来锁定。您将方法声明为 synchronized
,它隐式使用 方法针对 执行的 object 的实例作为锁定资源。
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.
}
查看输出有何不同。第二个线程必须排队等待第一个线程。
我有一个线程 class 具有以下两种方法:
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 部分,使用鼠标单击方法打开文件选择器 window 让用户选择文件。代码
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() 唤醒第一个线程,以便它可以发送图像。
不要在 Swing 应用程序中直接使用线程 API,而是使用 Swing workers,当您需要执行后台任务时,只需创建线程的实例,例如发送图像,而您不需要阻止 GUI 线程
看来您正在等待线程对象,而 gui 对象正在执行通知。
所以当你这样做时notifyAll();
不要指望等待线程对象被唤醒,因为那是一个完全不同的锁。
您可以使用普通锁。
如@MadProgrammer 所述,您没有在同一个锁上进行同步。锁,好吧,不知道还能怎么描述它。这是一把锁。要在 Java 中锁定并等待,您可以选择一个 object 来表示 "lock"。
如果 2 个线程在 2 个不同的 object 上同步,就像第一个线程说 "I am pumping gas in pump #1, if you need to use it, get in line",然后第二个线程说 "Hey, let me know when you're done with #2"(当泵 2 停止服务时) .
如果您希望第二个 driver 等待第一个 driver 完成泵送,那么他需要声明对泵 #1 的兴趣,与其他人持有的同一个泵.同样,如果你想让2个线程成功执行等待和通知,他们需要引用相同的object.
为什么这在您的情况下可能显得令人困惑,因为您没有指定 explicit objects 来锁定。您将方法声明为 synchronized
,它隐式使用 方法针对 执行的 object 的实例作为锁定资源。
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.
}
查看输出有何不同。第二个线程必须排队等待第一个线程。