`
yydcj
  • 浏览: 59944 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

奇怪的notify()与notifyAll()的执行问题

阅读更多

摘自http://www.javaworld.com.tw/jute/post/view?bid=5&id=72452&sty=1

 

於 2004-09-28 14:49 user profile send a private message to user reply to post reply to post search all posts by select and copy to clipboard. 
ie only, sorry for netscape users:-) add this post to my favorite list


大家好!我是Java新手!
我發現一個問題捏!

notifyAll()可以通知所有等待它的執行緒,
我測試用notify()的結果也會通知所有的執行緒捏!
請問它們最大的差別在哪呢?

執行環境:j2sdk1.4.2_05 + Eclipse3.0

package concurrent;

class Y extends Thread {
	  int total;
	  public void run() {
	    synchronized(this) {
	      while(total < 50) {
	        try {
	          Thread.sleep(500);
	        } catch(InterruptedException ie) {}
	        total++;
	      }
	      notify();
	    }
	  }
	}
	 
	public class ClassOne implements Runnable {
	  Y ty;
	  
	  ClassOne(Y ty) {
	    this.ty = ty;
	  }
	  
	  public void run() {
	    synchronized(ty) {
	      try {
	        ty.wait();
	      } catch(InterruptedException ie) {}
	      System.out.println(Thread.currentThread().getName() + " Be notify()");
	    }
	  }
	  public static void main(String[] args) {
	    Y ty = new Y();
	    ClassOne x = new ClassOne(ty);
	    
	    Thread t1 = new Thread(x, "t1");
	    Thread t2 = new Thread(x, "t2");
	    Thread t3 = new Thread(x, "t3");
	    t1.start();
	    t2.start();
	    t3.start();
	    ty.start();    
	  }
	}
 

於 2004-10-03 04:52 user profile send a private message to user send email to Duncan reply to post reply to post search all posts by select and copy to clipboard. 
ie only, sorry for netscape users:-) add this post to my favorite list

經過我與其他版主的討論,這可以說是一個 bug 或是說這是一個令人意想不到 side effect(我沒留意到有哪份官方文件有提到這一點)。

原 因在於 Thread object 結束時(成為 dead thread)會(在自己身上)執行 notifyAll method,這一點可以從 Thread - join method 看出來(當一個 thread T1 invoke join(0) or join() 在另一個 thread object T2 身上,T1 thread 會 block 住,直到 thread T2 成為 non-alive thread)。

public final synchronized void join(long millis) 
    throws InterruptedException {
	long base = System.currentTimeMillis();
	long now = 0;

	if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
	}

	if (millis == 0) {
	    while (isAlive()) {
		wait(0);
	    }
	} else {
	    while (isAlive()) {
		long delay = millis - now;
		if (delay <= 0) {
		    break;
		}
		wait(delay);
		now = System.currentTimeMillis() - base;
	    }
	}
    }
 



可以看到 Thread - join method 是以 synchronization 的機制來實做,當 join 的 actual argument value 為 0 是採用 wait(0) 來讓 caller thread block 住,wait(0) 執行後不會因為 timeout 過了而讓 caller thread wake up,可以想見 Thread class 的底層實做一定有在 run method 執行完畢而 Thread object 所啟動的 thread 成為 dead thread 時,有 invoke notifyAll 在 Thread object 身上,以便 wake up 其他因為 join(0) or join() invocation 而 block 住的 thread,否則其他的 thread 便一直停駐在紅色 的那一個 statement 處。

你試著把 Y - run method 中的 notify method call 拿掉,其他的 thread 還是會自動 wake up,在 ty thread 成為 dead thread 之後。

你把 Y instance 以 Thread 包裝起來執行,就可以避開這問題。

public class ClassOne implements Runnable {
    public static void main(String[] args)
    {
        Y ty = new Y();
        // [略] ...
        new Thread(ty).start();
    }
}
 

 

 

分享到:
评论
1 楼 hadesmile 2010-11-29  
确实是个问题,不过一般不这样用,

相关推荐

Global site tag (gtag.js) - Google Analytics