Topic: 一个奇怪的wait()问题?

  Print this page

1.一个奇怪的wait()问题? Copy to clipboard
Posted by: jiangns3000
Posted on: 2003-07-09 19:24

几乎所有的JAVA教科书都说,线程若调用了wait(),当发生如下三种情况时,
thread T then lies dormant until one of three things happens:
1)Some other thread invokes the notify method for that object and thread T happens to be the one arbitrarily chosen as the one to notify.
2)Some other thread invokes the notifyAll method for that object.
3)If the call by thread T to the wait method specified a timeout interval, the specified amount of real time has elapsed. The thread T is then removed from the wait set and re-enabled for thread scheduling
可是如下JAVA程序都不是上述三种情况,却正常运行。

该程序调用了好几个wait(),却没有一个notify()或notifyAll(),为何这些wait()不永远等待下去?


public class Reader extends Thread {
Calculator c;
public Reader(Calculator calc, String name) {
c = calc;
setName(name);
}

public void run() {
synchronized(c) {
try {
System.out.println(getName()+" Waiting for calculation...");
c.wait();
} catch (InterruptedException e) {}
}
System.out.println( getName()+" cal.total: " + c.total);
}

public static void main(String [] args) {
Calculator calculator = new Calculator();

new Reader(calculator, "1").start();
new Reader(calculator, "2").start();
new Reader(calculator, "3").start();
new Reader(calculator, "4").start();
new Reader(calculator, "5").start();

calculator.start();
}
}

class Calculator extends Thread {
int total;

public void run() {

System.out.println("Starting calculating ...");

synchronized(this)
{
for (int i = 0; i < 100; i++) {
total += i;
}
try {
wait(1000);
} catch (InterruptedException e ) {}

}

}
}


程序运行结果是:
1 Waiting for calculation...
2 Waiting for calculation...
3 Waiting for calculation...
4 Waiting for calculation...
5 Waiting for calculation...
Starting calculating ...
2 cal.total: 4950
3 cal.total: 4950
4 cal.total: 4950
5 cal.total: 4950
1 cal.total: 4950

2.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: rostone
Posted on: 2003-07-11 10:17

I think
The two methods maybe cause this problem:
c.wait();
calculator.start(); //calculator and c is the same object/thread

Who can give an authoritative explanation?

3.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: jiangns3000
Posted on: 2003-07-14 11:08

都说用了wait(),必须用notify()或notifyAll()来唤醒,即二者配套使用。该程序表明不是这么一回事,这该如何解释呢?没有书,没有知识;尽信书,不如无书。唉。。。

4.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: nov1
Posted on: 2003-07-14 19:50

When a thread exits, it will issue a notify()/notifyAll() on objects from which it has occurred a lock.

5.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: jiangns3000
Posted on: 2003-07-14 22:24

但是这一点从来没有在资料中有说明或记载呀。你是从该程序中推断出的呢,还是有一个好的参考中得知的呢?能提供一个参考处吗?

6.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: floater
Posted on: 2003-07-15 00:18

Hehe, the best reference is the java doc:

java code:
public final void wait() throws InterruptedException {
  wait(0);
}

now let's check wait(long t):
Causes current thread to wait until another thread invokes the
* {@link java.lang.Object#notify()} method or the
* {@link java.lang.Object#notifyAll()} method for this object, or
* some other thread interrupts the current thread, or a certain
* amount of real time has elapsed.
* <p>
The last "or" case is telling you something, it will wait that period of time.

So if you want to do a "real" testing, set the time to 10^20, you should see they stays there. Further, you may call notify to interrupt them during this long period of time.

7.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: nov1
Posted on: 2003-07-15 00:26

I knew it before seeing your post. A thread will definitely do some cleanup job when it exits, releasing locked resources and notify other threads are two of them.

Maybe you can find a clue from the doc at:

http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html

And you can read Java Language Spec and VM Spec to gain more knowledge about this. Good luck.

8.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: jiangns3000
Posted on: 2003-07-15 10:20

Thank you very much!

9.Re:一个奇怪的wait()问题? [Re: nov1] Copy to clipboard
Posted by: rostone
Posted on: 2003-07-15 13:27

nov1 wrote:
When a thread exits, it will issue a notify()/notifyAll() on objects from which it has occurred a lock.


Maybe it is correct.But it can not explain this phenomena.
If we comment the "synchronized" sentence as below:

class Calculator extends Thread
{
int total;
public void run()
{
System.out.println("Starting calculating ...");
/*
synchronized(this)
{
for (int i = 0; i < 100; i++)
{
total += i;
}
try
{
wait(1000);
}
catch (InterruptedException e )
{
}
}*/
}
}

The calculator thread didn't lock any object.So it would not call any notify as you expected when it expired.

But you can see the same result.

10.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: jiangns3000
Posted on: 2003-07-15 17:50

对rostone的贴子中提的问题,这又是为什么呢?这个问题我还是感到有些费解。请问谁能给出一个较权威的解释?总版主floater先生,能否给些建议:这个门该怎么摸到它、走出去?

11.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: nov1
Posted on: 2003-07-15 22:23

There are three issues here:

1, The mechanism of a dying thread releasing locked resources
2, The mechanism of a dying thread notifying other threads
3, The criteria of objects being selected for step 1 and 2

I do not want to talk too much about low level implementation, let us focus on things at API level.

Java use keyword synchronized to explicitly lock on an object, lock is put when entering synchronized method or block, and released when exiting the method or block. Keyword synchronized has a built-in function which to notify other threads who also use keyword synchronized.

Wait and notify rely on synchronized machanism, an object is not allowed to wait or notify if it has yet been keyword synchronized, namely not been locked by keyword synchronized. But wait/notify is different from a lock, because wait/notify is not a lock but a communication among threads.

Now it's clear that wait/notify is a communication tool among threads. Keyword synchronized IMPLICITLY use this tool automatically talk with other threads' keyword synchronized. But it does not affect threads who EXPLICITLY use wait/notify.

Besides keyword synchronized and explicit wait/notify calls, another implicit client of this communication tool is a dying thread.

As to my knowledge, for step 3, only the object on which the dying thread was running would be selected. On this object, the dying thread will issue a notify to other threads who have been forced sleep by either keyword synchronized or wait method. The purpose of the last message is to avoid dead lucks.

This means I was wrong on one thing, I said:

"When a thread exits, it will issue a notify()/notifyAll() on objects from which it has occurred a lock."

A dying thread does not issue a notify for objects it once locked. I can testify it by following program:

It does not issue a notify for object c.lock, though it had a lock on it.

public class Reader
extends Thread
{
Calculator c;

public Reader(Calculator calc, String name)
{
c = calc;
setName(name);
}

public void run()
{
synchronized(c.lock)
// synchronized(c)
{
try
{
System.out.println(getName()+" Waiting for calculation...");
c.lock.wait();
// c.wait();
}
catch (InterruptedException e)
{}
}
System.out.println( getName() + " cal.total: " + c.total);
}

public static void main(String [] args)
{
Calculator calculator = new Calculator();

calculator.start();

new Reader(calculator, "1").start();
new Reader(calculator, "2").start();
new Reader(calculator, "3").start();
new Reader(calculator, "4").start();
new Reader(calculator, "5").start();
}
}

class Calculator
extends Thread
{
public Object lock = new Object();

int total;

public void run()
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e )
{}

System.out.println("Starting calculating ...");

synchronized(this.lock)
// synchronized(this)
{
for(int i = 0; i < 100; i++)
{
total += i;
}
}
}
}

12.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: jiangns3000
Posted on: 2003-07-16 09:04

Great! Thank nov1 very much!

13.Re:一个奇怪的wait()问题? [Re: nov1] Copy to clipboard
Posted by: rostone
Posted on: 2003-07-16 09:38

nov1 wrote:
There are three issues here:

1, The mechanism of a dying thread releasing locked resources
2, The mechanism of a dying thread notifying other threads
3, The criteria of objects being selected for step 1 and 2



Good!
Could I say:
1.A dying thread will release any its locked resources.
In fact, it releases the resource as soon as it exists the "synchronized{}" statement which has locked this resource and then notify other threads which are waiting on this resource.

2.A dying thread will notify other threads which are waiting on this dying thread.

thanks

14.Re:一个奇怪的wait()问题? [Re: rostone] Copy to clipboard
Posted by: floater
Posted on: 2003-07-16 11:08

rostone wrote:
Maybe it is correct.But it can not explain this phenomena.
If we comment the "synchronized" sentence as below:

class Calculator extends Thread
{
int total;
public void run()
{
System.out.println("Starting calculating ...");
/*
synchronized(this)
{
for (int i = 0; i < 100; i++)
{
total += i;
}
try
{
wait(1000);
}
catch (InterruptedException e )
{
}
}*/
}
}

The calculator thread didn't lock any object.So it would not call any notify as you expected when it expired.

But you can see the same result.

I don't get your point because I don't think this is relevent. The key is in other threads' sync blocks because others stop at wait() because entering your commented sync block.

15.Re:一个奇怪的wait()问题? [Re: nov1] Copy to clipboard
Posted by: floater
Posted on: 2003-07-16 11:29

nov1 wrote:
There are three issues here:

1, The mechanism of a dying thread releasing locked resources
2, The mechanism of a dying thread notifying other threads
3, The criteria of objects being selected for step 1 and 2

I do not want to talk too much about low level implementation, let us focus on things at API level.

Java use keyword synchronized to explicitly lock on an object, lock is put when entering synchronized method or block, and released when exiting the method or block. Keyword synchronized has a built-in function which to notify other threads who also use keyword synchronized.

Wait and notify rely on synchronized machanism, an object is not allowed to wait or notify if it has yet been keyword synchronized, namely not been locked by keyword synchronized. But wait/notify is different from a lock, because wait/notify is not a lock but a communication among threads.

Now it's clear that wait/notify is a communication tool among threads. Keyword synchronized IMPLICITLY use this tool automatically talk with other threads' keyword synchronized. But it does not affect threads who EXPLICITLY use wait/notify.

Besides keyword synchronized and explicit wait/notify calls, another implicit client of this communication tool is a dying thread.

As to my knowledge, for step 3, only the object on which the dying thread was running would be selected. On this object, the dying thread will issue a notify to other threads who have been forced sleep by either keyword synchronized or wait method. The purpose of the last message is to avoid dead lucks.

This means I was wrong on one thing, I said:

"When a thread exits, it will issue a notify()/notifyAll() on objects from which it has occurred a lock."

A dying thread does not issue a notify for objects it once locked. I can testify it by following program:

It does not issue a notify for object c.lock, though it had a lock on it.

public class Reader
extends Thread
{
Calculator c;

public Reader(Calculator calc, String name)
{
c = calc;
setName(name);
}

public void run()
{
synchronized(c.lock)
// synchronizedCoffee
{
try
{
System.out.println(getName()+" Waiting for calculation...");
c.lock.wait();
// c.wait();
}
catch (InterruptedException e)
{}
}
System.out.println( getName() + " cal.total: " + c.total);
}

public static void main(String [] args)
{
Calculator calculator = new Calculator();

calculator.start();

new Reader(calculator, "1").start();
new Reader(calculator, "2").start();
new Reader(calculator, "3").start();
new Reader(calculator, "4").start();
new Reader(calculator, "5").start();
}
}

class Calculator
extends Thread
{
public Object lock = new Object();

int total;

public void run()
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e )
{}

System.out.println("Starting calculating ...");

synchronized(this.lock)
// synchronized(this)
{
for(int i = 0; i < 100; i++)
{
total += i;
}
}
}
}


You lock is an ordinary object, not a thread, so it doesn't automatically send a notify() either.

In general, each object has a wait set(according to spec and some book) which is a set of Threads(spec 17.14).

In general, we need to explicitly call notify() or notifyAll() to wake up these threads. See 17.14.

But somehow this Thread class is exceptional. When the thread finishes, it, as an object, *automatically* call notifyAll() to wake the Threads in its own wait set(waking them up is just the first step to make them run, see books & spec).

http://forum.java.sun.com/thread.jsp?forum=31&thread=421020

A very interesting observation. I haven't found anywhere elese other than the above link mentioned.

My 2 cents.

16.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: nov1
Posted on: 2003-07-16 22:43

<pre class=codeStyle>
class T extends Thread or implements Runnable
{
public void run()
{
......
......
// following line of code is either inserted by compiler
// or implemented by JVM (who cares?)
// it is up to JVM provider
this.notify();
}
}
</pre>

A line of code says a thousand of words, does it?

17.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: jiangns3000
Posted on: 2003-07-17 08:31

我确实不知道nov1先生说的在run()中由编译器或JVM自动插入this.notify()或this.notifyAll()是否是真的?我想说的是:
1)notify()或notifyAll()必须在synchronized块中,它怎么能说插入就插入?这个this.notify()所需要的synchronized块由谁来保证?难道每一个run()中又会自动的synchronized?若是这样,那JAVA线程的效率就。。。?
2)为何不将这个责任交给JAVA程序员?(因为毕竟是由于我们看到有wait()而没有相应的notify()或notifyAll()才产生该问题的)。
请哪一位好心人能读一读程序所生成的汇编指令程序,看一看它到底是怎么弄的?有没有插入notify()或notifyAll()。

18.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: nov1
Posted on: 2003-07-17 09:08

******

19.Re:一个奇怪的wait()问题? [Re: jiangns3000] Copy to clipboard
Posted by: floater
Posted on: 2003-07-17 21:34

No, it's not in the byte code and it shouldn't because it's a runtime behavior.

Where did you get the code? Can you trace back?


   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923