synchronized thread queuing slow ?
Hye,
Here is a little testing code:
publicclass Main
{
static Object o;
publicstaticvoid main(String[] args)
{
o =new Object();
Thread1 t1 =new Thread1( 1);
Thread1 t2 =new Thread1( 2 );
t1.start();
t2.start();
}
publicstaticclass Thread1extends Thread
{
int number;
public Thread1(int num)
{
number = num;
}
publicvoid run()
{
try
{
int i = 1;
while(true )
{
synchronized(o)
{
System.out.println(number +": o is mine " + i);
Thread.sleep(1000);
System.out.println(number +": don't want o anymore " + i);
i++;
}
//Thread.sleep(1);
}
}
catch(Exception e)
{
System.out.println(e.toString());
}
}
}
}
It is a "ping-pong"-like program between 2 threads which are synchronized on a single object o.
The thing is, if I don't put a sleep after the synchronized block, the 2nd thread will never have access to the object.
If I uncomment the Thread.sleep, the two threads "ping-pong" gently.
Any idea about this ?
[2549 byte] By [
Garf1242a] at [2007-10-3 4:57:29]

Sleep doesn't release the lock. If you use o.wait(with a time) you'll release the lock giving other threads a chance to exec. But since the other thread wants the lock, it will wait for your first thread to release it.
If you want to get a feel for threads talking to each other, use wait() / notify().
If youi want to get a good feel, read the java.concurrent. section on interface Condition. There is a good example of two threads using await() / signal().
I should have explain a bit more my question:
During first thread t1 synchronized block execution, t2 is waiting for t1 to unlock o.
I thought that at the end of t1 synchronized block execution, t1 would unlock o, and as t2 was waiting for that, t2 would have locked o and execute its own synchronized block.
But that doesn't seem to work like that unless t1 sleeps a little bit before trying to lock o again.
So, my question was: does JVM check for other threads waiting for a resource exactly when leaving a synchronized block ? Because it seems to be a bit late in that example, so that t1 has enough time to request the lock on o, and be in the "lock request list" like t2 when JVM decides which thread will have the lock.
We don't know what code the compiler + hot spot generated for the while(true) etc.
It may have in-lined everything so there is no break. That is: when T1 exits the sync block it never really exits, just goes back to the print and sleep etc.
The second sleep forces the compiler + hot spot to add code that is not synchronized.
I'm just guessing. Perhaps others have a different look at this?
Indeed you are guessing...!
The compiler may well have unrolled the loop, but given that it's an infinite loop, it would seem very unlikely. And even if it had, it would still be required to generate the appropriate monitor release statements at the end of the synchronised block - even if the very next statement is a monitor acquire. To do otherwise would mean it was arbitrarily changing the semantics of the code.
OP: the behaviour of the system is non-deterministic. The operating system will schedule threads for execution when it sees fit. The effect of this (particularly when coupled with Java's synchronisation semantics) is that you can see some fairly unexpected (although perfectly legal) execution orders.
If you want the two threads to run the way you describe, you need to use some other mechanism to force that to happen, otherwise you are at the mercy of the OS.
A guess is a guess. No good programmer would write such code.
There is no way out of the loop except by exception.
There is a Java tool to print the compiled class. I don't know of one to print the hot spot generated instructions.
As you said, the free/acqure for the monitor may be on top of each other giving no break for other threads.
The things we see here!
Monitor acquisition is not fair - barging is allowed - which means that a thread that releases a lock and immediately tries to grab it again will likely do so. This *shouldn't* lead to long term starvation however, but it could be a while before the other thread gets a turn. The details depend on exactly what version of the VM , which platform etc.
The lesson to take away from all this is to not make any assumptions about scheduling order or queuing order. The two basic rules of concurrent programming in Java:
1. Assume that threads can be interleaved in any way, so always protect access to shared mutable state.
2. Never require that threads be interleaved in some particular way. If you need to control the order in whic things happen you have to enforce that ordering youself using appropriate synchronization tools.
Why don't you write a single thread that calls the required methods alternately?
ejpa at 2007-7-14 23:02:47 >

> Why don't you write a single thread that calls
> the required methods alternately?
because it's not real development code: it's java experimentation.
Anyway, thank you for your answers. Now I know that java monitor acquisition follows Murphy's law, so that you must take all the precautions you can when you do concurrent programming in Java.
A correction. I thought the VM tried to avoid indefinite postponement but it doesn't. Basically in the sample code when the monitor is released by thread 1 it wakes thread 2 so that it can contend for the monitor, but thread 1 tries for the monitor itself and as thread 2 has been blocked, thread 1 will always win that race and prevent thread 2 from acquiring the monitor. So not only does thread 1 always get the monitor, thread 2 keeps waking up for nothing.