Hi, Im through SCJP book on synchronizing code. There is this example:
And everything goes fine - i get my account overdrawn and so on.
The strange thing is that when i put synchronized on makeWithdrawal method - that makes only one thread (always first to start) allowed to call makeWithdrawal. So i get something like that:
I've tried it countless times but it always acts the same way. I know that "countless" is not appropriate word when we talk about "not guaranteed" behavior of scheduler, but lest say i've run it 100 times and effect is always the same. Is it possible that its my JVM specific behaviour?
This question is proabaly better suited for the Threads and Synchronization forum. I'm sure a bartender will kindly move it over there for us.
Originally posted by Pawel Nowacki:
that makes only one thread (always first to start) allowed to call makeWithdrawal.
It won't always be the first one. This is simply what is happening on your PC based on what you are doing. For example, on my PC I was seeing Fred go first. But then by doing this:
in the main method, enough of a delay was introduced that I started seeing Lucy first "all" the time.
Basically, the reason you are seeing the one thread do all its transactions first is that the work is run fast enough that the one thread completes before the thread scheduler gives the second thread a go at it and it is able to do some work. For example, change loop so it loops through 200 times:
Also, increase the initial balance to 1000 so you can see the withdraws ping pong between the two users before the overdrafts start.
Run that and you will eventually see the second thread gets a go at it and the withdraw attempts will bounce between Lucy and Fred.
So it's not so much your JDK, but the speed of of CPU and the behavior of the Thread scheduler on your machine.
Keep in mind, simulating threading behavior and delays is very hard; especially on small scales.
Another thing you can do, is introduce a delay in the withdraw method so that the other thread is given a chance. Here I use a random delay to more simulate potential real behavior. The key is this: it must at some point sleep for longer than the 1000 ms delay when simulating the withdraw. By using a random time, it prevents always seeing Fred, Lucy, Fed Lucy, Fred Lucy... all the way through on every run.
This isn't the best way to to do things in production code. But for an example and simulation, it works.
Joined: Nov 14, 2008
Thank you Mark. Yes, increasing number of loops makes it visible. Although i did it before i must have not spot it. Threads seems to be more subtle subject. Here things are not certain and one must use grater scale and amount of time to see real nature of it. Just out of curiousity - how actually does the scheduler work? Is it some probability generator involved (After all its the most fair thing there is )
Just out of curiosity - how actually does the scheduler work? Is it some probability generator involved (After all its the most fair thing there is )
There's no easy answer to that question. There are actually some fairly complex algorithms involved. From the Wikidpedia Multithreading article:
A major area of research is the thread scheduler which must quickly choose among the list of ready-to-run threads to execute next as well as maintain the read-to-run and stalled thread lists. An important sub-topic is the different thread priority schemes that can be used by the scheduler. The thread scheduler might be implemented totally in software or totally in hardware or as a hw/sw combination.
In the case of Java, the issue is made a bit more complex because the Java Virtual Machine manages some of the thread scheduling, but the OS handles a majority of it. And every OS will operate a bit differently. So you might get different results on a Windows XP machine as compared to a Windows Vista PC as compared to a Linux PC. Then throw in the difference of a single CPU machine versus a multiprocessor machine, and the subject gets more involved.
Additionally, there is the matter of priority. Threads can be assigned different priorities. If you read the API Documentation for the Java Thread class, you will see it states:
Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon. When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon.
That is a very high-level overview of the subject. If you take a look at Java Threads, 3rd Edition (ISBN-13: 978-0-596-00782-9) -- which by the way is co-authored by Henry Wong, the moderator of the Threads forum here at JavaRanch -- Chapter 9 is dedicated to the subject of Thread Scheduling. I'd recommend picking up a copy and giving it a read. Java Concurrency in Practice (ISBN-13: 978-0-321-34960-6) makes a great followup book. [ December 30, 2008: Message edited by: Mark Vedder ]