【问题标题】:Understanding Java Wait and Notify methods了解 Java 等待和通知方法
【发布时间】:2011-02-07 03:29:33
【问题描述】:

我有以下程序:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class SimpleWaitNotify implements Runnable {

final static Object obj = new Object();
static boolean value = true;

public synchronized void flag()  {
    System.out.println("Before Wait");
    try {
        obj.wait();
    } catch (InterruptedException e) {
        System.out.println("Thread interrupted");
    }
    System.out.println("After Being Notified");
}

public synchronized void unflag() {
    System.out.println("Before Notify All");
    obj.notifyAll();
    System.out.println("After Notify All Method Call");
}

public void run() {
    if (value) {
        flag();
    } else {
        unflag();
    }
}

public static void main(String[] args) throws InterruptedException {
    ExecutorService pool = Executors.newFixedThreadPool(4);
    SimpleWaitNotify sWait = new SimpleWaitNotify();
    pool.execute(sWait);
    SimpleWaitNotify.value = false;
    SimpleWaitNotify sNotify = new SimpleWaitNotify();
    pool.execute(sNotify);
    pool.shutdown();

}

}

当我等待 obj 时,对于两个线程中的每一个,我都会收到以下异常 Exception in thread "pool-1-thread-1" java.lang.IllegalMonitorStateException: current thread not owner

但是如果我使用 SimpleWaitNotify 的监视器,那么程序执行就会暂停。换句话说,我认为它会暂停当前的执行线程,进而暂停执行程序。任何有助于了解正在发生的事情的帮助将不胜感激。

这是一个理论和 javadoc 看起来很简单的领域 1,由于示例不多,因此在概念上给我留下了很大的空白。

【问题讨论】:

    标签: java multithreading wait


    【解决方案1】:

    您在obj 上调用waitnotifyAll,但您在this 上进行同步(因为您有同步方法)。

    为了等待或通知,您需要先“拥有”监视器。取消同步方法,改为在 obj 上同步:

    public void flag()  {
        System.out.println("Before Wait");
        synchronized (obj) {
            try {
                obj.wait();
            } catch (InterruptedException e) {
                System.out.println("Thread interrupted");
            }
        }
        System.out.println("After Being Notified");
    }
    
    public void unflag() {
        System.out.println("Before Notify All");
        synchronized (obj) {
            obj.notifyAll();
        }
        System.out.println("After Notify All Method Call");
    }
    

    【讨论】:

    • 太棒了。完全摆脱复合对象obj 可以达到同样的效果吗?
    • @Maddy:您应该能够等待并通知“this”——但这通常是个坏主意,因为“this”通常是其他代码可以有效访问的引用。保持对只有您的代码知道的对象的私有引用是一种很好的做法。
    【解决方案2】:

    objsynchronize,或在this 上致电waitnotify。调用线程必须持有调用这些方法的相同对象的监视器。

    例如,

    synchronized void flag() {
      System.out.println("Before Wait");
      try {
        wait();
      } catch (InterruptedException e) {
        System.out.println("Thread interrupted");
      }
      System.out.println("After Being Notified");
    }
    

    在这个例子中,锁被持有在this(当修饰符synchronized用于实例方法时,获取实例的监视器)。因此,wait() 方法可以在隐含实例 this 上调用。


    为了协调两个线程,它们需要共享相同的锁。原始版本有一个静态的obj 可以用作锁,但它没有在synchronized 块中使用。这是一个更好的例子:

    class SimpleWaitNotify implements Runnable {
    
      private final Object lock;
      private final boolean wait;
    
      SimpleWaitNotify(Object lock, boolean wait) {
        this.lock = lock;
        this.wait = wait;
      }
    
      public void flag()  {
        synchronized (lock) {
          System.out.println("Before Wait");
          try {
            lock.wait();
            System.out.println("After Being Notified");
          } catch (InterruptedException ex) {
            System.out.println("Thread interrupted");
          }
        }
      }
    
      public void unflag() {
        synchronized(lock) {
          System.out.println("Before Notify All");
          lock.notifyAll();
          System.out.println("After Notify All Method Call");
        }
      }
    
      public void run() {
        if (wait) {
          flag();
        } else {
          unflag();
        }
      }
    
      public static void main(String[] argv) throws Exception {
        ExecutorService pool = Executors.newFixedThreadPool(4);
        Object shared = new Object();
        SimpleWaitNotify sWait = new SimpleWaitNotify(shared, true);
        pool.execute(sWait);
        SimpleWaitNotify sNotify = new SimpleWaitNotify(shared, false);
        pool.execute(sNotify);
        pool.shutdown();
      }
    
    }
    

    【讨论】:

    • 我改为等待 SimpleWait 对象本身。但是,在这种情况下,程序不会停止。而是不通知挂起的线程。我得到以下打印。之前等待之前通知所有之后通知所有方法调用
    【解决方案3】:

    不如直接声明pool.shutdown(),试试如下。

    while (!service.isTerminated())
    {
        service.shutdown();
    }
    

    所以它会一直等到所有线程执行完成。

    【讨论】:

      猜你喜欢
      • 2015-01-26
      • 1970-01-01
      • 2011-10-30
      • 2018-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多