Reputation: 11
I am running this java thread example :
public class Locks1 extends Thread {
private Object lock;
private int myId;
public Locks1( Object l, int id ) {
lock = l; myId = id;
}
public void run() {
synchronized( lock ) {
for ( int i = 0; i < 3; i++ ) {
System.out.println( "Thread #" + myId + " is tired" );
try {
Thread.currentThread().sleep( 10 );
} catch ( InterruptedException e ){
} System.out.println("Thread #" + myId + " is rested" );
}
}
}
public static void main( String args[] ) {
Integer lock = new Integer( 0 );
for ( int i = 0; i < 4; i++ ) {
new Locks1( lock, i ).start();
}
}
}
And I am having this result:
Thread #0 is tired
Thread #0 is rested
Thread #0 is tired
Thread #0 is rested
Thread #0 is tired
Thread #0 is rested
Thread #3 is tired
Thread #3 is rested
Thread #3 is tired
Thread #3 is rested
Thread #3 is tired
Thread #3 is rested
Thread #2 is tired
Thread #2 is rested
Thread #2 is tired
Thread #2 is rested
Thread #2 is tired
Thread #2 is rested
Thread #1 is tired
Thread #1 is rested
Thread #1 is tired
Thread #1 is rested
Thread #1 is tired
Thread #1 is rested
I don't understand why it prints in this order. Can anyone please help me to understand why the sequence is 0321 instead of 0123?
Thanks
Upvotes: 0
Views: 248
Reputation: 1535
In your code, the first issue is that lock resource has to be a final object so declare it like this :
final Integer lock = new Integer( 0 );
As without this semantics, different threads might be locking on the different object however operating on the same object.
And an explanation to the behaviour you observed.
While the goal maybe to improve performance overall, using multiple threads always introduces some performance costs compared to the single threaded approach. These include the overhead associated with coordinating between threads(locking, signaling, synchronization),increased context switching,thread creation and teardown, and scheduling overhead. ref.ch-11.1
As stated, locking and context switching and signalling is associated with multithreading as compared to single threaded programs. In your case, the reason you get the sequence "0321" is not something reproducible in another machine for example.
The Thread.start()
method invokes the system native method start0
and the system allocates resources and if the thread locks any resources (which it does). As your method takes time (however small) to complete the run()
method the other threads are on wait
A simple difference changing your code to this will make a different output. As this introduces differences in the timing and scheduling of which thread the processor resumes and acquires the next lock on Integer lock
. In short, this is not a reproducible output and will be different in the 1001 try "may be".
final Integer lock = new Integer( 0 );
for ( int i = 0; i < 4; i++ ) {
System.out.println("starting : " + i);
new Locks1( lock, i ).start();
}
outputs:
starting : 0
starting : 1
Thread #0 is tired
Thread #0 is rested
Thread #0 is tired
Thread #0 is rested
Thread #0 is tired
Thread #0 is rested
Thread #1 is tired
Thread #1 is rested
Thread #1 is tired
Thread #1 is rested
Thread #1 is tired
Thread #1 is rested
starting : 2
Thread #2 is tired
Thread #2 is rested
Thread #2 is tired
Thread #2 is rested
Thread #2 is tired
Thread #2 is rested
starting : 3
Thread #3 is tired
Thread #3 is rested
Thread #3 is tired
Thread #3 is rested
Thread #3 is tired
Thread #3 is rested
NOTE: This again might not be reproducible in your machine.
Upvotes: 2
Reputation: 18077
When several threads are waiting to acquire a lock and it finally becomes available, there is no guarantee what thread will be chosen. It can be any one. If you execute the test several times, you might get different results.
Upvotes: 0