• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Simple Question Regarding Single Runnable Instance and Synchronized/Volatile

 
Ranch Hand
Posts: 71
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This has been kind of bugging me for a while - so I hope you folks can clarify this for me regarding a single-instance Runnable with multiple-threads and the Synchronized/Volatile abilities...

Most of the examples I've seen of using Runnable with Thread was always this pattern (for 2 Thread Examples):

1. Create "Test" Class that implements Runnable
2. Instantiate "Test" Runnable Object from that Class - twice - (eg: TestRunner1 object and TestRunner2 object)
3. Put TestRunner1 object with Thread1 instantiation, start Thread1.
4. Put TestRunner2 object with Thread2 instantiation, start Thread2.

And then the example goes onto to talking about Synchronized and Volatile. Why are so many examples like this - and don't instead just have the Runnable Class instantiated "once" and put that same runnable object (Runner1 into Thread1 and Thread2?)

So my example would be:

1. Create "Test" Class that implements Runnable
2. Instantiate a single "Test" Runnable Object - (eg: TestRunner1 object )
3. Put TestRunner1 object with Thread1 instantiation, start Thread1.
4. Put TestRunner1 object with Thread2 instantiation, start Thread2.


From what I understand - the whole utility of using "Synchronized" and "Volatile" comes from the fact that the multiple threads need to come from the "single same original" Runnable object for it to work.

If you instantiate "two" Runnable objects and put them each into a distinct Thread - the "Synchronized" and "Volatile" abilities don't really do anything - because they are from two "distinct" Runnable object (though borne from the same Class) - right?
 
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Perry Terrance wrote:From what I understand - the whole utility of using "Synchronized" and "Volatile" comes from the fact that the multiple threads need to come from the "single same original" Runnable object for it to work.


No, that is not the case. Synchronization is about protecting the data or signaling a condition, not about Runnables. The fact that the data is almost always in a different class or Object than the runnable is why most good tutorials and samples use different runnables. It forces you to synchronize using the same scope as the data, which is the important part.

Volatile is more of the same, but is about publishing the data rather than protecting it. It really is completely separate from what is running it and were, and shouldn't be thought of in reference to the Runnable at all.

Perry Terrance wrote:If you instantiate "two" Runnable objects and put them each into a distinct Thread - the "Synchronized" and "Volatile" abilities don't really do anything - because they are from two "distinct" Runnable object (though borne from the same Class) - right?


If you use them correctly, then no, not right. If the data is all instance data and not shared between threads then yes, the use of synchronization is not necessary. But if any data is shared between the instances then the synchronization is important - as long as it is performed on the correct object.

It is a lot easier to discuss specific examples. Do you have example code that you think doesn't do anything or does it wrong?
 
Perry Terrance
Ranch Hand
Posts: 71
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the response Steve, I in fact do have a dummy project right now to use as an example:

EXAMPLE 1


Running this code gives me the following:



My Understanding of What's Happening:

This code obviously has a single Runnable instance put into 2 separate Threads. The "count" is an instance field in that object, but the fact that it was put into 2-Threads caused this instance field to essentially be "cached" into each of the Thread instances with its own "copy" - thus making 2 copies of itself of the "count" field-value.

This can cause issues where the Thread1 of the "count" field could be 3, while at the same moment the Thread2 of the "count" field still be 2 - correct? However - in the end - they do seem to add to each other - and therefore can create an output even up to "7". This is again because I am assuming that BOTH threads are feeding off the same "object" - and therefore will still need to resolve itself in the end of what the "count" instance field sum is...




 
Perry Terrance
Ranch Hand
Posts: 71
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Now let's alter the code a bit and try this:

EXAMPLE 2


The output now looks like this:



My Understanding of What's Happening:

By moving the Runnable instantiation inside the loop - we are now creating "2" Runnable instances and binding it to a separate thread.

Because now these 2 Threads are running 2 Distinct Runnable instances - the output is "guaranteed" never to go above 4 - because the "count" fields now are totally independent of one another and do not "stack" - as in the first example since they are 2 separate Runnable objects. Thus they can go up to 4 max and that's it...


 
Perry Terrance
Ranch Hand
Posts: 71
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Now here is a 3rd variation:

EXAMPLE 3


Console Output:



My Understanding of What's Happening:

Same as Example 2 - except we now have the "Count" as a static field. And it makes a big difference.

This is because while there are still 2 separate Runnable objects in 2 separate Threads - because it is "Static" - it will try to grab the class value of "ProcessingThread" and try to add it up to the best of its abilities. Now - notice how I said - "best of its abilities" because static-fields still are NOT thread-safe (the class value of the "ProcessingThread" is locally "cached" in individually in each thread with their own "copy") - so there will be instances where the local copy of Thread1's static "count" value can be 1, while Thread2's static "count" value can be 2.

Again - while static fields are based upon the ClassLoader (and are supposedly very stable and solid in single-thread applications), when threading comes into play - this whole stability of static fields gets thrown out the window...

But I think the JVM will try to resolve itself in the end - which is why it still "stacks/adds" up to 7...
 
Perry Terrance
Ranch Hand
Posts: 71
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Steve - please let me know if my understanding of the first 3 Examples are correct. I know I haven't even mentioned Synchronized or Volatile yet, but I want to make sure my understanding of these first examples are good before we move on....
 
author
Posts: 23951
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Perry Terrance wrote:Steve - please let me know if my understanding of the first 3 Examples are correct. I know I haven't even mentioned Synchronized or Volatile yet, but I want to make sure my understanding of these first examples are good before we move on....



It is actually hard to say one way or another -- mainly because the three examples are doing different things, and hence, hard to compare. Furthermore, two of the three are not thread safe, meaning have race conditions that make the output vary. The one example that is arguably thread safe is example two. With example two, there are race conditions that can affect the order of the output, but the results are always the same -- the two variables always end up as 4, and the last output is always 3 (the 4 is never printed). With the other examples, the output results may variable, as they are changing one variable, in a non-thread safe manner.

Anyway, with the data known so far, I say your understanding are correct -- my opinion may change once you start applying synchronization though...

Henry
 
reply
    Bookmark Topic Watch Topic
  • New Topic