This is mostly useless, yeah.
You have 10000 threads. Each thread is going to perform the following task pattern:
NB: Take the object "Test2.class" (the instance of java.lang.Class
that represents the Test2 class; there is only one such object in the entire VM loaded. We shall call this 'the locker'.
Check the locker object for its 'monitor' thread. If it is unset, set yourself as the monitor thread of the locker and continue. (and do all that atomically). If not, freeze the thread until the 'monitor' is null again, and then compete with the 9999 other threads that want to set it; only one of the 9999 wins, sets itself as the monitor, and continues. The remainining 9998 will freeze and wait another round.
Execute doActionA
. All the while, 9999 threads are twiddling thumbs.
Relinquish the locker (unset yourself as the monitor of the locker). 9999 other threads all fly in to set themselves as monitor. Only one of those will 'win'.
Acquire the lock again (set yourself as the monitor of the locker if it is currently unset; otherwise, freeze and wait until it is available.. and do that atomically). Depending on the JVM implementation, this thread may in fact 'win', and take the monitor riiight back, beating the other 9999 threads.
Execute doActionB
. During this job, 9999 threads are twiddling thumbs doing absolutely nothing whatsoever. Just waiting around.
Relinquish the monitor and exit. Pfew. 9999 more to go.
As you can tell, this pattern most likely means this code runs as fast as just:
for (int i = 0; i < 10000; i++) {
doActionA();
doActionB();
}
except the above most likely runs FAR faster, as your example first allocates 1.25 gigabytes worth of memory just to store stacks (each thread needs a stack, and here's praying your stacks are 'just' 128k large, they are often larger), and wastes a ton of time juggling thread states for pretty much no purpose.
This is not how you thread things.