views:

85

answers:

1

Will following 2 code block achieve the same result. What is the difference better then, if any?

class test {
 Object obj = new Object();

 void test(){
  synchronized(obj){

  }
 }

 void test1(){
  synchronized(this){

  }
 }
}
+7  A: 

No, they don't do the same thing. One of them acquires the monitor on "this", and the other acquires the monitor on the object referred to by obj.

Normally it's a better idea to synchronize using a private variable, never exposing that variables value to any other code. That means you know that the code in your class is the only code which will be synchronizing on that object, which makes your code easier to reason about. If you synchronize on any monitor which other code could also synchronize on (including the this reference) you've got much more code to reason about when considering thread safety, deadlocking etc.

Jon Skeet
Viktor Klang
@Viktor: If you need to expose the lock used, I would do so explicitly - but I'd only do that when I absolutely had to.
Jon Skeet
The problem is that you're in that case making decisions for the user of your code. The problem behind all this is the violation of encapsulation that locks produce. Take ConcurrentHashMap as an example, there's no way to perform any operation while holding the segment lock, because someone decided that was a good idea. So, whenever you need to have an atomic operation on CCHM you're either forced to hack the source, or inherit from it and put your class in java.util.concurrent because some of it's most important methods are package scoped.
Viktor Klang
@Viktor: Sure... but I still think this is preferable to just locking on "this" - especially if you don't document where you're doing so. If you're going to document what you're locking on, you might as well create a property to get at the lock reference so that at least if people are going to acquire the same lock, they'll definitely be doing so deliberately.
Jon Skeet
@Jon Skeet: Absolutely, but that simply doesn't scale. (Compare Hashtable to CCHM)
Viktor Klang
@Viktor: So what's your proposed alternative? In my experience it's fine for *most* classes to be effectively thread-neutral; isolate threading behaviour in a few key places which ideally to very little *other* than threading.
Jon Skeet
@Jon Skeet: If you go with locks you need to either be able to inject behavior (taking a callback instead of a value) or expose the lock (if someone will consume your code), or use STM. As an example: http://github.com/viktorklang/transactors/blob/master/src/main/scala/STM.scala
Viktor Klang
@Viktor: *If* your clients need that atomic behaviour, yes. I'd say that in many cases it's overkill though. There are times and places for relatively advanced techniques (of various types) but I wouldn't start putting them everywhere just in case... especially as I suspect *most* developers probably don't write general purpose public APIs... they write code within a corporate environment, where if a need for change arises, it can be handled then.
Jon Skeet
@Jon Skeet: Absolutely, if you control the source from end-to-end, it's cheaper to do nothing until the need arises. I'm just saying that hiding locks is a double-edged sword.
Viktor Klang