wood burning stoves 2.0*
The moose likes Performance and the fly likes Threading odd/even Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of The Java EE 7 Tutorial Volume 1 or Volume 2 this week in the Java EE forum
or jQuery UI in Action in the JavaScript forum!
JavaRanch » Java Forums » Java » Performance
Bookmark "Threading odd/even" Watch "Threading odd/even" New topic
Author

Threading odd/even

Matthew Thomson
Greenhorn

Joined: May 10, 2012
Posts: 2
I couldn't decide if this should be in the threading sub-forum or here, but seeing as the question is performance related...

Anywho, yes this is my first post, hello :-); I am self learning Java during my time on the bench at work and have written a little program that alternates incremental and printing of a number based on whether it is odd or even.

Now, I tested this against the following code:

I expected the threaded one to be faster, although I have no idea why... so my question is this: is there a way I can improve the performance of the first code block to match and possibly exceed that of the second code block?

Edit: Also, if you think "why did he do that" or "this could have been smaller if he'd wrote it like x" please do not hesitate to inform me. I hope to take the certification for Java within the next two weeks to present to any possible clients, so any help is appreciated.
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Using multiple threads can improve performance. It can do so if a) You have CPU-bound tasks that can execute independently of each other, and at least as many CPUs/cores as threads, or b) You have I/O and CPU work, or different kinds of I/O that can be done independently of each other. The whole idea of using multiple threads is that there are tasks that can execute at least somewhat independently of each other, and one can be using one resource, while another uses another resource. (E.g., one uses the CPU while the other waits on I/O, or one uses CPU-1 while the other uses CPU-2.)

In your case, however, your multiple threads are not operating independently. They're taking turns, so only one can execute at a time. So you're still counting sequentially, not letting separate pieces run concurrently, AND on top of that you're adding sync/wait/notify overhead. If, instead, you had one thread counting 1, 3, 5, etc. and the other thread counting 2, 4, 6, etc., with no sync/wait/notify, then you'd have a chance of getting a performance benefit from multiple threads. (Of course, that model doesn't work if you're just tying to increment a single shared variable 1, 2, 3, etc.).

Additionally, since each thread is doing a tiny bit of CPU-bound work and then a much, much more expensive I/O operation on a shared I/O resource, even if you did let them run in parallel, the delay introduced by the shared I/O resource would almost certainly negate any gain from parallelizing the CPU work.

Finally, I didn't think about it too hard, so I may be off base here, but I think you want one thread waiting while %2 == 0 and the other while %2 != 0. That won't change the fact that you're still doing stuff sequentially and adding pointless mulithreading overhead, but just thought I'd mention it.


Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Jeff Verdegan wrote:
you're adding sync/wait/notify overhead.
...
Additionally, since each thread is doing a tiny bit of CPU-bound work and then a much, much more expensive I/O operation on a shared I/O resource, even if you did let them run in parallel, the delay introduced by the shared I/O resource would almost certainly negate any gain from parallelizing the CPU work.


To clarify a bit: You can still get a performance gain from multithreading even when using sync/wait/notify or doing I/O, but you need to be doing a large enough amount of work relative to the overhead of waiting for a mutually-excluded resource such as a lock or a particular Stream/Reader/Writer to offset that overhead.
Matthew Thomson
Greenhorn

Joined: May 10, 2012
Posts: 2
Thanks for the information, I just assumed having it running across two threads would be a benefit without taking the time to think about it. But hey, at least I managed to get the concept to work, which was, the ultimate goal.

Also the "%2 == 0" is different with a (!(%2 == 0)), I prefer rendering a not on the whole statement to "!=".
Deepak Bala
Bartender

Joined: Feb 24, 2006
Posts: 6661
    
    5

Your first code block involves a lot of context switches and synchronization. Synchronization is known to introduce a heavy overhead. Moreover like Jeff pointed out, it is not necessary to introduce multi-threading in your code to increment a variable. The second code block may well be faster than the first considering these overheads.

Now, if you ever come across a situation where incrementing / decrementing counters need to be thread safe across multiple threads, I would suggest the use of atomic variables. They simplify this process greatly.

http://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html


SCJP 6 articles - SCJP 5/6 mock exams - More SCJP Mocks
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Matthew Thomson wrote:
Also the "%2 == 0" is different with a (!(%2 == 0)),


Ah, didn't see that.

I prefer rendering a not on the whole statement to "!=".


I think you'll find you're in the minority there. If you're even developing on a team--either for a school project or in your job--you'll probably be expected to use more conventional idioms. (I certainly wouldn't allow the !(%2==0) style in my team's code.) Just something to think about.
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2337
    
  28


Jeff Verdegan wrote:

To clarify a bit: You can still get a performance gain from multithreading even when using sync/wait/notify or doing I/O, but you need to be doing a large enough amount of work relative to the overhead of waiting for a mutually-excluded resource such as a lock or a particular Stream/Reader/Writer to offset that overhead.


Just to give a visual on this. Think of threads as lanes on a highway, and synchronization/IO as merge points on the highway. When there is low traffic; ie; most of the lanes on the highway are empty and one has cars (most threads are idle) the traffic will zip right through without delay. OTH, when you have heavy traffic, all the cars on all the lanes will be slowed down and traffic starts getting backed up. How much the traffic gets backed up depends on how big your choke point is (ie; how much work you are doing inside your synchronization block)

Actually, depending on how big the choke point is, you might be better having a single lane road than a multi-lane road. The drivers have to merge, so they have to slow down to make sure they don't hit anyone. There is an overhead with forcing the cars to merge. If you had a single lane road throughout, the cars would get by much faster

In your case, your 2 threads are spending almost all of their time inside the synchronization block. The only part outside is the part that evaluates while(true) which is nothing. You are much better having a single lane road.
Rohan Dhapodkar
Greenhorn

Joined: Jun 27, 2011
Posts: 23
Deepak Bala wrote:

Now, if you ever come across a situation where incrementing / decrementing counters need to be thread safe across multiple threads, I would suggest the use of atomic variables. They simplify this process greatly.

http://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html


I implemented this solution using AtomicIntegers @ http://rohandhapodkar.blogspot.in/2012/04/print-odd-and-even-numbers-using-two.html
Jeff Verdegan
Bartender

Joined: Jan 03, 2004
Posts: 6109
    
    6

Rohan Dhapodkar wrote:
I implemented this solution using AtomicIntegers @ http://rohandhapodkar.blogspot.in/2012/04/print-odd-and-even-numbers-using-two.html


That solution is rather convoluted and complex, and the spin locks, such as:


are pure evil.

Here's a somewhat simpler, cleaner, and much less CPU-hungry solution:

 
jQuery in Action, 2nd edition
 
subject: Threading odd/even