• 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

Atomic Variables vs Synchronization

 
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Ranchers, comrades

I am working on a multithreaded program right now and since I am using Tiger (JSE 1.5), I decided to use all those nice toys that come along with it.

Looking for a way to reduce synchronization at minimum I have used atomic variables (you know, the classes in the java.util.concurrent.atomic package).

And just to make sure I am not doing something stupid I would like to confirm my understanding on these matters.

If I have this code:



Now, this code ensures that only one thread at the time can change the var1 or var2 variables. While one thread is modifying var1, another thread cannot modify neither of them.

Now, please correct me if I am wrong.

This code is not the same thing:



Because altough it ensures that var1 and var2 will be written atomically and their values will be seen by all threads, it does not guarantee that var1 cannot be modified while var2 is altered by another thread.

Hence, if I am right, this kind of behaviour just can be implemented with synchronization.

Is all this right?

[ April 08, 2006: Message edited by: Edwin Dalorzo ]
[ April 08, 2006: Message edited by: Edwin Dalorzo ]
 
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, as far as I know, you are totally and absolutely right.
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the confirmation, Ilja.

Sometimes we all need to hear a sencod opinion just to make sure we understood what we thought we understood.
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I disagree. As far as I can tell, from the code shown here, there is no practical difference between the two code examples. If one thread modifies var1 "simultaneously" with another thread modifying var2 - so what? How is that observably different from one thread acting a tiny bit before, or a tiny bit after, the other? The operations defined in the synchonized code are identical in effect to the operations in the atomic code. As long as every synchronized method does no more than a single atmic method call can do, there is no real difference between the two coding techniques. Except that the atomic code is probably faster.

Now there is another issue here - since in each case var1 and var2 are not private, it's possible for other code in te package to access them in ways not show in the code so far. And depending what that other code does, there may or may not be an important difference between the two coding techniques. Also, there's no code show which actually reads the values, or does any output. So far, nothing shown here has any observable effects at all. If code is added later - well we can't really say much about what effect that will have unless we see it.

If we make all the variables private (as they should be, right?) and add some getter methods for each variable, comparable to the existing setters (meaning, synchronized or atomic, the same way as the setters), and no other code is added - then the two code samples are equivalent in effect, regardless of what is done in other classes. (Well, assuming no uses of refection or bytecode engineering to violate encapsulation.)

If you think there's a difference between the code samples - can you add some code to show some output, and then give an example of an observable difference? Some output that could occur with atomic code but not synchronized code, or vice versa? So far the code doesn't do anything to be able to talk meaningfully about possible differences in observable output.
 
author
Posts: 23951
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Unfortunately with these code examples, using Atomic variables is just like using volatile variable. In fact, the private field in the Atomic variable that is holding the int, is declared volatile. You need to see more complex examples, before you appreciate the benefits of Atomic variables.


Anyway...

Atomic variables were provided for a technique called optimistic locking. Optimistic just means that we are optimistic that synchronization is not necessary -- and don't. Of course, to make it work, the operation can actually fail.

In this example, it can't fail. It is just a set operation. However, Atomic variables also provide a conditional set operation -- set the variable to a particular value only if it is set to another value. As such, you can do a complex operation like this...



In this case, you are calculating a really complex result (using a temp third variable) and then swap the old value with the new value. If two threads are doing this in parallel, only the first swap will succeed. The second operation will report a failure, as its origval is not correct.

To improve this, you can also do this...



In this case, while the operation can fail, our method will not. We will just keep retrying the operation until it succeeds. So... if two threads happens to execute at the same time, the first to save the result will succeed. And the second will throw everything away and try again with the new value stored by the other thread.

Notice that we did a really complex calculation without a single synchronization. The operations actually run in parallel...

On the other hand, we had to throw away calculations when collisions occurred...


BTW, you can build on these operations to do some really complex stuff.

Henry
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks yo you all for the feedback.

Well, it was not my intention to use this code as a real life practical example.

I just wanted to prove the theory the with atomic variables it is possible that two threads modify the two values simultaneously, whily with synchronization it is not possible.

I am currently writing a multithreaded application. I have several threads reading from a MQ queue. When the queue is emtpy I make the thread to wait. At the end I leave only one thread running. When this thread discovers that there are messages again in the queue it notifies a thread, and so on and so on.

In other to control the waiting mechanism I have two static integer variables, the waitingThreads, and the runningThreads.

The runningThreads increase once a thread starts the run method and decrease when the run method ends.



Now, to put a thread to wait I have to check that it is not the last running thread.

This is some pseudocode logic:



Now, at the very beginning I thought the variables waitingThreads and runningThreads were good candites for AtomicVariables.

However, look at this foreseeable concurrency problem that arise from the use of just atomic variables, without any locking mechanism over more complex operations that imply the modification of several variables:

1. T1 -> reads the queu and discovers is empty
2. T2 -> an error happens in T2 and start finilization
3. T1 -> reads the waitingThreads variable and it is 0
4. T1 -> reads the runningThreas varialbe and it is 2 and
then enter the waiting block
5. T2 -> decrements runningThreads
6. T2 -> discovers there is still one running thread and do not notify
(this is because the waitingThreads is not incremented yet)
7. T2 -> finishes execution
8. T1 -> increments waiting threads and waits forever because there are no
running threads to notify it.

Now, I understand the points that you have set, when it comes to just reading the value of a variable or just assigning a new value, I will be fine with volatile varibles.

On the other hand, if I have to do increments or variable comparison before assigment I may use atomic variables.

However, atomic variables will not ensure, by themselves the atomicity of an operation that modifies multiples atomic variables, because other threads could be modifying those same varibles concurrently.

This last point is a conclusion of mine while developing this code, and I just wanted to make sure that it is correct. That is why I wrote this thread here at Java Ranch.

What do you, guys, think of this particular case?

Thanks in advance
Edwin Dalorzo
[ April 09, 2006: Message edited by: Edwin Dalorzo ]
 
Henry Wong
author
Posts: 23951
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

However, atomic variables will not ensure, by themselves the atomicity of an operation that modifies multiples atomic variables, because other threads could be modifying those same varibles concurrently.

This last point is a conclusion of mine while developing this code, and I just wanted to make sure that it is correct. That is why I wrote this thread here at Java Ranch.



Interestingly, it is possible to modify multiple variables concurrently -- but you really need to know what you are doing... The level of difficulty seems to increase at a faster pace than with syncronization. For example...



In this case, we are using an atomic reference to point to 4 variables simultaneously. In our complex operation, we will recalculate the new values for those 4 variables using temp variables. Once we are done with all 4 variables, we will set all 4 variables with an atomic compare and set.

If there is a collision with two threads simultaneously trying to modify the variables, only the first will succeed. The other thread will simply throw away the data, and retry using the values set by the first thread.

Henry
 
Henry Wong
author
Posts: 23951
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

What do you, guys, think of this particular case?



Personally, I would *not* recommend using atomic variables for an I/O bound operation -- such as reading from and writing to message queues. The threads will spend most of their time waiting for data -- either to write to the queue or from the queue.

Henry
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Interesting approach that you propose, Henry. Frankly, I did not know I could do that.

In this particular example that you wrote, if I am getting it correctly, the calculations will repeat when any concurrent modification of any of the variables happens.

That means that if the concurrency is unlikely to happen this approach may increase performance since it does not use synchronization. However, if the concurrency happens too often then it would be necessary to evaluate what is more expensive: waiting for the contended lock or recalculating the variables again.

Another question:
Do you have any idea about how to control fairness with this approach, Henry?

I mean, if I were using synchronization with a ReentrantLock I could stablish lock fairness in true as an attempt to make sure that all waiting threads will ever get executed.

In this example you wrote (I know that for exaplanation purposes and for that very simple and self-explanatory), there is no way to know if a thread never comes out of the loop. I mean, if the number of executing threads increase, there are chances that a calculating thread is always behind all other threads making the same calculations, hence, never coming out of the loop.

Any thoughts regarding this particular issue? is it a drawback of the approach?

Once again, Ilja, Jim and Henry, thanks for the feedback. This conversation is resulting very enlightening.
[ April 09, 2006: Message edited by: Edwin Dalorzo ]
 
Henry Wong
author
Posts: 23951
142
jQuery Eclipse IDE Firefox Browser VI Editor C++ Chrome Java Linux Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Interesting approach that you propose, Henry. Frankly, I did not know I could do that.



I don't have the smarts to propose such a technique...

"Optimistic Locking" techniques have been around for a long time. You can probably google volumes about it. And yes, it can get incredibly complex.

In this particular example that you wrote, if I am getting it correctly, the calculations will repeat when any concurrent modification of any of the variables happens.

That means that if the concurrency is unlikely to happen this approach may increase performance since it does not use synchronization. However, if the concurrency happens too often then it would be necessary to evaluate what is more expensive: waiting for the contended lock or recalculating the variables again.



Yes. "Optimistic" techniques is not a magic bullet. There are cases where it will be slower than synchronization.


Another question:
Do you have any idea about how to control fairness with this approach, Henry?

I mean, if I were using synchronization with a ReentrantLock I could stablish lock fairness in true as an attempt to make sure that all waiting threads will ever get executed.



"Fairness" implies some sort of shared resource -- like a lock. In the example, there is no such resource. This is *not* to say that there is no way to be fair. I guess some sort of fairness can be worked into the algorithm.

Henry

Henry
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks a lot for your help, Henry.

I will take all your advises into account.

By the way, I read your book. Java Threads, 3th Edition.

I liked it. Good job. I guess I should thank you for that, too

Though as Java beginner I have to say that I feel that sometimes the chapter examples get complicated with non-thread related stuff (like Swing) that I, personally, find distracting.

I will be looking forward reading more of your work in the future.

Once again, thank you.

Regards,
Edwin Dalorzo.
[ April 09, 2006: Message edited by: Edwin Dalorzo ]
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic