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

时间:2013-04-08 19:03:20

标签: java multithreading wait notify

我有跟随方法foo,它接受​​一个Observer并将当前线程置于休眠状态,直到Observer唤醒它。

出于某种原因,我在java.lang.IllegalMonitorStateException

中不断收到foo例外
public void foo(Observer o)
{
    Thread currentThread = Thread.currentThread();
    o.setThread(currentThread);
    // sleep until the observer wakes it
    currentThread.wait(2000);   // <<<<< Exception happens here
}

Observer对象稍后会在其currentThread.notifyAll()调用Observable时调用update

public class Observer
{
    private volatile Thread currentThread;
    // ... other code  ....

   public void setThread(Thread t)
   {
       currentThread = t;
   }

   public void update(Observable o)
   {
        currentThread.notify();
   }
}

知道这里有什么问题吗?

5 个答案:

答案 0 :(得分:3)

每当您调用对象的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);   
    }
 }

更新:
根据您的要求,我建议您在wait对象上调用Observer。所以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
   }
}

答案 1 :(得分:2)

  

这与这个问题不一样。我不能把同步放在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更改的内容。

答案 2 :(得分:1)

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

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

其他线程,稍后可以调用f.release来取消阻止其他线程

答案 3 :(得分:0)

要使用java.lang.Object.wait()您必须拥有显示器,通常由synchronized block完成:

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

}

答案 4 :(得分:0)

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