File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Beginning Java and the fly likes TestThreads Code Magnets exercise Head First Java Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "TestThreads Code Magnets exercise Head First Java" Watch "TestThreads Code Magnets exercise Head First Java" New topic
Author

TestThreads Code Magnets exercise Head First Java

Mike Chen
Greenhorn

Joined: Jul 05, 2010
Posts: 5
Hi everyone,

Sorry this problem is so specific, but can someone with the Head First Java, Second Edition please help me? This Exercise can be found in Chapter 15 pp. 524-526. I have a link to the Google Books section of this which includes pp. 525-526 (http://books.google.com/books?id=5VTBuvfZDyoC&lpg=PP1&dq=head%20first%20java&pg=PA526#v=onepage&q=testThreads&f=false). Pg. 524 just presents the 4 class declarations. I have been doing the exercises in this book diligently and this is the first one that I got to that really stumped me and really made me feel incompetent. I have a few lingering questions about this: it seems as though the solution presented in the book is one that seems to rely a bit on the timing of the thread scheduler, which the book explicitly states you should not do. Are there any instances where something might go awry if you do this sequential flip-flopping of threads using Thread.sleep? There are certainly times when the thread will sleep even if it isn't asked to right? So wouldn't this screw up the idea that the threads will alternate perfectly in turn? I ask this because I received completely inconsistent outputs when running the solution as explicitly entered from pg. 526. I was only able to achieve the desired output when I put in status messages in ThreadOne and ThreadTwo in order to debug, but I don't see why those would change the output. It was seemingly random, and I got numbers ranging as low as ~73000. This really doesn't seem like it makes sense even if the timing between the threads is horribly off, since ThreadOne should still increment the counter by 1000 for 98 iterations and ThreadTwo should still increment the counter by 1 for 99 iterations. Is something just wrong with my computer? Please help! Thanks!
Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2835
    
  11

Multithreading is certainly mind-boggling, and can be error prone. Just to be clear, what is the output you expect.

Threads will not "sleep" without being asked to, but they will yield control, or more accurately have control taken away from them when their time slice ends. By sleeping, a thread voluntarily removes itself for a time from be allocated a time slice. Since you have two threads here, if one is sleeping, the other one will get all the processing time. If both are sleeping, which will certainly happen in this example, then it will just look like a pause to your program.

I actually wouldn't expect any output. I haven't had to manage my own threads for awhile, but I remember if you started threads, and then the main method ended, the whole program would exit, and it would take the threads down with it, whether they were done or not. To allow the threads to finish, you would have to call Thread.join() on them.

If you're getting output at all, then that's clearly not the case, so maybe there have been some improvements in thread management. You're right that you could get the output lines in either order. The "one" output line should print "one: 970xx" and the two output line should print two: "xx098", where xx might be 98 or 99 or something below. If you see something fundamentally different, go ahead and post it here.
Mike Chen
Greenhorn

Joined: Jul 05, 2010
Posts: 5
Hi Greg,

Thanks a lot for your response. The output we were aiming for in the code magnets exercise was

one 98098
two 98099

The goal of the Code Magnets exercises is that they give you a target output and you are supposed to rearrange the magnets to give you code that will give you the desired output. Like I said in my OP, I did receive output every time, and even the target output a few times out of the MANY times I ran it, but for the most part I got incredibly variable outputs. I can't remember right now but I will post a few as soon as I get on my old computer. I can understand if the threads just crashed and didn't produce any output but the baffling part is that it does reach the println statements at the end of the threads, which means that the codeUpdate methods just aren't iterating properly. Is it possible that the code is more consistent and predictable if run on another machine?
Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2835
    
  11

Ah, you're right: 98 and 99. So, I would expect your output to be either:

one 98098
two 98099

or

two 97099
one 98099

but there's a small chance it could be

one 98099
two 98099


Now, the method in Accumulator is not synchronized, probably because they haven't taught what that means yet. It shouldn't matter because it only has one statement (counter += add), which I think should be atomic. Atomic means control can't break off to the other thread in the middle of that statement. However, if you get strange output again, I'd like to see it. It's possible synchronizing would fix it. By the way, the bug you've found is called a race condition, which are notoriously hard to fix or even test for, because they doesn't always happen, and introducing a debugger, or even a print statement, might change the timing enough so it doesn't happen at all.
Mike Chen
Greenhorn

Joined: Jul 05, 2010
Posts: 5
Hi Greg,

They actually have already taught synchronized, and I didn't think it would be very useful in this method since, like you said, it only has one action. Anyway, I ran the program on my compiler at home and I came up with these whacky outputs:

one 81080
two 81080

one 92093
two 92093

one 69067
two 69067

I recompiled the classes and re-ran and my first output was this:

one 98098
two 98099

Followed by:
one 73085
two 73085

Any thoughts?
Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2835
    
  11

Hi Mike,

Yep, I typed it in and got the similar results you did. Then I synchronized the updateCounter() method, and after that everything worked. I always got 98099 for both outputs. What that means is "counter += add" is not actually atomic. It must be doing something like:

READ counter
ADD counter, add
WRITE counter

If that process gets interrupted in the middle we can lose some of our updates. I wouldn't have thought that likely, but there you go. It's an important lesson in synchronizing access to shared resources.
Mike Chen
Greenhorn

Joined: Jul 05, 2010
Posts: 5
Hi Greg,

Thanks for taking another look. I also got the same results by synchronizing the method. This is a vast improvement over the relatively random stuff I was getting earlier, but is there a way to get the target output, that is one 98098 two 98099 consistently?
Christian Ekiza
Greenhorn

Joined: Apr 03, 2011
Posts: 1
I have managed to get a consistent result as stated in the exercise by:
- synchronizing the update method
- inverting the order in which the threads are started (first start thread two and then start thread one)
- and by moving the sleep before the countUpdate in both threads.









This seems to get a consistent return of:
one 98098
two 98099
Ashish Ramteke
Ranch Hand

Joined: Oct 24, 2012
Posts: 86
    
    1
Hello, Christian Ekiza!
I came accross the same exercise in the book and there was the same problem regarding its output. Actually, I even posted the problem on this website in the "Threads and Synchronization" forum (here: http://www.coderanch.com/t/602483/threads/java/Java-program-unexpectedly-giving-results) because I thought that forum is best suited for this topic. Then in the "Similar Threads" section below found the link to this post. Its great to see that using the changes you suggested the output is coming exactly as it is expected! Though to me the problem, because of it the output was inconsistent, is not clear, the modification in the program takes me a step closer to the clear understanding of the working of compiler/interpreter/Scheduler of Java.


Good day..! :-)
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: TestThreads Code Magnets exercise Head First Java
 
Similar Threads
Why doesn't this code work in Netbeans 7.0?
OutputStream implementation
Use of Private Constructor in Thread Example
The static synchronized methods of the same class always block each other as only one lock per class
Threads/Looping: How Can This Be?