Win a copy of Design for the Mind this week in the Design forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

How to make a class thread safe

 
Swapnil Shroff
Ranch Hand
Posts: 58
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have a following class



What is the least costly way to make this class thread safe

Thanks
 
Henry Wong
author
Marshal
Pie
Posts: 21000
76
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Since both method calls are atomic operations, I would say that the "least costly" method is to just change the variable to volatile. Like such...



Henry
 
Henry Wong
author
Marshal
Pie
Posts: 21000
76
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The followup question is, of course, what if *not* all of the methods are atomic operations? For example...



Then you have two choices. You can synchronize the access like so...



Or you can use optimistic locking like so...



Now, as to which is faster, it would depend on how they are used. But in the general case, the second should be faster.

Henry
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24208
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Henry Wong:

Now, as to which is faster, it would depend on how they are used. But in the general case, the second should be faster.


Interesting! Not contradicting you at all, Henry, I'm just not as familiar with java.util.concurrent as I should be. Can you cite evidence for this claim? I didn't think any of the java.util.concurrent stuff used native magic; if so, it's going to be using synchronization under the hood, so I would guess the performance would be a wash (if it's not slower due to the one extra indirection, that is.) You're the expert here, though, so I'm looking forward to your reply.
 
Henry Wong
author
Marshal
Pie
Posts: 21000
76
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Ernest Friedman-Hill:

Interesting! Not contradicting you at all, Henry, I'm just not as familiar with java.util.concurrent as I should be. Can you cite evidence for this claim? I didn't think any of the java.util.concurrent stuff used native magic; if so, it's going to be using synchronization under the hood, so I would guess the performance would be a wash (if it's not slower due to the one extra indirection, that is.) You're the expert here, though, so I'm looking forward to your reply.


Yup, it does accomplish this feat by using "native magic"...

We did the testing a few years ago, for the update of the book. And what we saw was...

For simple operations, where the lock was not contended, there was very little improvement. For contended locks, (but small number of threads) the improvement was very measureable. As the number of threads increased, the optimistic locking collisions increased -- it was still better than synchronization, but less so.

Now, by "general case", I have to qualify it to, "within the limits of our tests". The main issue was that these were simple operations, since it was not really possible to define a test case, that we can use to apply to the general case. Our optimistic locking test was also dependent on how it recovers from a collision.

Henry
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24208
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks!
 
Swapnil Shroff
Ranch Hand
Posts: 58
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
But what if I make it like



Is it still thread safe?
 
Henry Wong
author
Marshal
Pie
Posts: 21000
76
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Swapnil Shroff:
Is it still thread safe?


If the getName() or setName() methods were not atomic, then the answer is definitely "no".

In theory, the answer is also "no". It is possible for a compiler to inline the method, in combination of caching the variable, etc.


I am tempted to say "yes", because it should work, but quite frankly, I can also envision a new JVM, with new optimization techniques... so IMHO, I would say "no".

Henry
 
Swapnil Shroff
Ranch Hand
Posts: 58
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Henry
 
Mr. C Lamont Gilbert
Ranch Hand
Posts: 1170
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


Still effectively atomic no?
[ February 26, 2007: Message edited by: Mr. C Lamont Gilbert ]
 
Swapnil Shroff
Ranch Hand
Posts: 58
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think it is not atomic as it can be divided in to more simpler code like


Am I right Henry?
 
Henry Wong
author
Marshal
Pie
Posts: 21000
76
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Swapnil Shroff:
I think it is not atomic as it can be divided in to more simpler code like

Am I right Henry?


Yes, that is the easiest way to look at it.

Officially, however, it depends on the code itself. For example, a post increment of an int, is not atomic, because the compiler generates a separate get and set operation. As such, it is possible for the int to actually change between the get and set operation.

In this case, it is possible for the string to change, between the time the string is loaded, appended, and then stored back into memory. This means that it is possible for two threads, to call the append method, and for one of the appended strings to be lost.

Henry
 
Mr. C Lamont Gilbert
Ranch Hand
Posts: 1170
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just to clarify, I said effectively atomic.

Originally posted by Henry Wong:

...In this case, it is possible for the string to change, between the time the string is loaded, appended, and then stored back into memory. This means that it is possible for two threads, to call the append method, and for one of the appended strings to be lost.

Henry



No moreso than with

Which you did call atomic right? The point I am making is they share the same level of atomicity.
[ February 26, 2007: Message edited by: Mr. C Lamont Gilbert ]
 
Henry Wong
author
Marshal
Pie
Posts: 21000
76
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Mr. C Lamont Gilbert:
Just to clarify, I said effectively atomic.

No moreso than with

Which you did call atomic right? The point I am making is they share the same level of atomicity.


Actually (assuming the volatile example for safety)... I don't agree.

For example, let's say that the original name was "orig". And two threads try to set it, one to "one" and the other to "two". The result will either be "one" or "two". There is actually no way, it can be a third choice.

In the append method example, let's say that the original name was "orig". And two threads try to append to it, one with "one" and the other with "two". The results should either be "origonetwo" or "origtwoone". However, this is not true -- it is actually possible to get "origone" or "origtwo". This is because the append method is not "effectively" atomic.

For a better look at "effectively" atomic, let's take a look at the optimistic locking version.



At first glance, this method is not atomic, as it is possible to change the value, from the get() to the set(). However, in this version, the set is actually an atomic compare and set, which means that the operation will fail, if another thread changes the value between the get and the set.

In the example, if another thread changes the value between the get and set, it will simply retry the operation. So... while it is possible to get between the get and the set, the method will keep retrying until it is not interfered with. It is "effectively" atomic.

Henry
 
vu lee
Ranch Hand
Posts: 206
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Since both method calls are atomic operations, I would say that the "least costly" method is to just change the variable to volatile

Since volatile prevents each thread to have its own local copy of the variable, suppose thread A, while in the middle of updating the variable, is being swapped out by the thread scheduler, what would be the current value of the variable. Would other threads be permitted to read the variable while it is currently modified by thread A.
 
Andrei Hager
Greenhorn
Posts: 10
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think "least costly" needs to be fleshed out a bit. If you're not expecting much contention on the protected data, and are playing it safe more than anything else, "cost" is the programming complexity you end up with, not a measure of performance.

Most synchronization techniques only show performance issues under high contention, and I doubt that a Student's name will change so much that it will matter in this case.

My "least costly" for this example would be to synchronize each method, and check that any private functions you have use the synchronized methods to get/set the name.

However, a Student with only a name is not worth much... if you add many other values and behaviors, you may want to look into a more complex synchronization scheme.
 
M Easter
Ranch Hand
Posts: 133
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My take: the danger is that "least costly" can imply "most clever".

From my reading/experience, one had better understand the JVM, the Java memory model, and more before attempting to be clever with respect to threads.

Correctness first, then measure, then optimize.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic