将当前线程置于睡眠状态,让其他线程唤醒它



我有以下方法foo,它接受一个观察者并将当前线程置于睡眠状态,直到观察者唤醒它。

由于某种原因,我在foo

中一直得到java.lang.IllegalMonitorStateException异常
public void foo(Observer o)
{
    Thread currentThread = Thread.currentThread();
    o.setThread(currentThread);
    // sleep until the observer wakes it
    currentThread.wait(2000);   // <<<<< Exception happens here
}

Observable调用update时,Observer对象将在稍后某个时间调用currentThread.notifyAll()

public class Observer
{
    private volatile Thread currentThread;
    // ... other code  ....
   public void setThread(Thread t)
   {
       currentThread = t;
   }
   public void update(Observable o)
   {
        currentThread.notify();
   }
}

你知道这是怎么回事吗?

无论何时调用对象的wait(long)notify()方法,该线程必须拥有该对象的监视器。因此,您应该将对象上调用wait()的代码块声明为synchronized。所以你的方法

public void foo(Observer o) 

应该按以下方式定义:

public void foo(Observer o)
{
    Thread currentThread = Thread.currentThread();
    o.setThread(currentThread);
    // sleep until the observer wakes it
    synchronized(currentThread)
    {
      currentThread.wait(2000);   
    }
 }

更新:
根据你的要求,我建议你应该在Observer对象上调用wait。所以foo的代码应该是这样的:

public void foo(Observer o)
{
    synchronized(o)
    {
      o.wait();//Don't pass time as parameter. Let only the Observer object to wake it up.
    }
 }

你的Observer类应该这样定义:

public class Observer
{
    // ... other code  ....
   /*public void setThread(Thread t)
   {
       currentThread = t;
   }*/
   public synchronized void update(Observable o)
   {
        notify();//Will wake up the Thread waiting on the current Object of Observer
   }
}

那和这个问题不一样。我不能把synchronized放在foo中,因为这会导致线程永远休眠。

我不认为你理解wait()notify()是如何工作的。你在线程上做而不是等待和通知,你在同一个对象上做。

currentThread.wait(2000);

它实际上导致当前线程等待它自己的Thread对象。notify()线程的方式是这样的:

Thread thread = new Thread(myRunnable);
...
thread.notify();

这是一个非常奇怪的模式,很可能不是你想要做的。哪个线程正在运行foo()方法并不重要。如果你正在使用一个线程池,你甚至不知道是哪个线程在运行它。

如果你想让Observer线程通知foo()中等待的线程,那么它们都需要使用相同的锁对象。比如:

class MyClass {
    ...
    public synchronized void foo() {
        // this is waiting on the current instance of MyClass
        wait(2000);
    }
}
public class Observer {
     ...
     // to wake up the other thread, we lock the same myClass instance
     synchronized (myClass) {
         // and notify that object
         myClass.notify();
     }
}

或者你可以创建一个它们共享的锁对象

final Object lockObject = new Object();
MyClass c1 = new MyClass(lockObject);
Observer obs = new Observer(lockObject();
...
class MyClass {
    private final Object lockObject;
    public MyClass(Object lockObject) {
        this.lockObject = lockObject;
    }
    ...
    public void foo() {
        // this is waiting on the current instance of MyClass
        synchronized (lockObject) {
            lockObject.wait(2000);
        }
    }
}
...
public class Observer {
    private final Object lockObject;
    public Observer(Object lockObject) {
        this.lockObject = lockObject;
    }
    public void update(Observable o) {
        synchronized (lockObject) {
            lockObject.notify();
        }
    }
}

供参考:锁对象应该几乎总是final,这样它们就不能改变它们的引用。你永远不会想要锁定像IntegerBoolean这样的变化。

我不希望你使用waitnotify,因为它是低级别的,如果没有很好地实现,很快就会变脏。可通过二进制信号量求解。

Semaphore sem = new Semaphore(0);
public void foo(Semaphore f){
    f.acquire();
}

其他线程,可以稍后调用f.release,这将解除阻塞其他线程

要使用java.lang.Object.wait(),您必须拥有监视器,它通常由同步块完成:

public void foo( Observer o ) throws InterruptedException
{
   Thread currentThread = Thread.currentThread();
   o.setThread( currentThread );
   synchronized( currentThread ) {
      currentThread.wait( 2000 );
   }
}

在notify()

周围添加相同的机制
public void update( Observable o ) throws InterruptedException {
   synchronized( currentThread ) {
      currentThread.notify();
   }

}

您可以使用同步的。当您调用currentThread.wait()时,线程将休眠并释放监视器(currentThread)。这个线程将等待另一个线程在同一监视器上使用notify()唤醒。

最新更新