简体   繁体   中英

Couple of questions regarding the synchronized keyword in Java (and C#'s lock)

  1. Are the following classes equivalent in Java? if no, why?

     class Abc { private int c = 0; 
     public synchronized void add(int a) { c += a; } public synchronized void subtract(int a) { c -= a; 
    \n\n } \n} \n\n\nclass Def { \n private int c = 0; \n private final Object lock = new Object(); \n\n\n
     public void add(int a) { synchronized(lock) { c += a; } } public void subtract(int a) { synchronized(lock) { c -= a; } 
    \n\n } \n} \n
  2. Also, what would be the problem of in Def , using this as synchronized parameter instead of lock ? Is the following the problem?

     Def def = new Def() synchronized (def) { def.add(5); //originates deadlock? or is this allowed AS LONG //as all this happens in the same thread? } 
  3. Are synchronized statements in Java just like C#'s lock statements? If no, what are their differences? If yes, why doesn't C# also allow to lock the methods, like Java allows?

  4. So I guess the problem with synchronized (this) can be depicted by the following example?

     class Xyz { private int c; 
      public void add(int a) { synchronized(this) { c += a; } } public void subtract(int a) { synchronized(this) { c -= a; } } public void show666() { return 666; } 
    \n\n} \n

    Thread1 calls xyz.add(0) and at the same time Thread2 tries to call xyz.show666() . Thread2 has to wait for Thread1 to finish with xyz.add(0) althtough it doesn't need any info directly related with the lock. Is that it?

  1. No they are different. using synchronized(reference){} obtains the monitor lock on the given reference (your lock object) and using synchronized in a method declaration uses this for the monitor lock. The net result is that an exteral caller can't obtain the same lock as the add and subtract methods.

  2. There won't be a deadlock, you can hold any number of monitor locks, plus the Def object uses a different object to lock on. But even if it was the first class Abc it won't deadlock. Synchronized locks in java are reetrant. So you can in theory attempt to lock them on the same thread as many times as you like.

  3. It's surprising that C# doesn't allow lock to be used on methods, but it does seem to be similar if not identical to the java synchronized keyword when used on a reference. One of the design goals of C# was to be familar enough for Java developers to be able to pick it up with out have there minds completely replaced, so I guess this isn't too surprising.

1 Are the following classes equivalent in Java? if no, why?

They differ by what instance they synchronize on and thus are affected by the differences between those instances.

Class Abc uses the Abc instance that the method is being invoked upon. Other code with access to the instance can use it to synchronize as well by explicitly using the instance in a synchronized block.

The synchronize code blocks in Class Def explicitly name the instance they synchronizes with. Since this instance is private to the Def instance, code external to Def cannot use it to synchronize (unless the instance is somehow leaked).

Some may argue that the Def approach is much safer , that it is important to encapsulate your locks for the same reason you should use private instance variables.

Finally, there are the differences between the synchronized keyword and using the synchronized statement, eg the synchronized statement can lock on any object, not just the instance of the executing code, the synchronize keyword is slightly more efficient, etc.

2a Also, what would be the problem of in Def, using this as synchronized parameter instead of lock?

No problem. Using synchronized keyword on an instance method is semantically identical to wrapping the code of the method in a synchronized block synchronized on this (the synchronized keyword is slightly more efficient). Using the synchronized keyword on a static method is the same as using a synchronized block synchronized on the class itself (eg synchronized(FooBar.class) { ... } ).

2b Is the following the problem?

No, locks in Java are reentrant, which just means that the thread holding the lock on the protecting instance can enter and exit any other code block synchronized on the same instance.

3a Are synchronized statements in Java just like C#'s lock statements? If no, what are their differences?

Semantically equivalent.

http://en.csharp-online.net/CSharp_FAQ:_What_is_the_difference_between_CSharp_lock_and_Java_synchronized#Synchronized_code_blocks

But note this answer about Monitor.Enter and Monitor.Exit

Are there any differences between Java's "synchronized" and C#'s "lock"?

3b If yes, why doesn't C# also allow to lock the methods, like Java allows?

It does - use the [MethodImpl(MethodImplOptions.Synchronized)] annotation.

http://en.csharp-online.net/CSharp_FAQ:_What_is_the_difference_between_CSharp_lock_and_Java_synchronized#Synchronized_methods

4 Thread1 calls xyz.add(0) and at the same time Thread2 tries to call xyz.show666(). Thread2 has to wait for Thread1 to finish with xyz.add(0) althtough it doesn't need any info directly related with the lock. Is that it?

No, a lot of people assume "locking" an instance affects the entire instance. It only affects synchronized code (synchronized methods and code within a synchronized statement) that is synchronized on that instance. Unsynchronized code is unaffected (at least until it hits a synchronized statement or calls a synchronized method).

The unsynchronized method show666() won't cause the thread to block. Nothing changes if the synchronized(this) statements were changed into synchronized methods - again show666 won't block (unless its synchronized too).

  1. They are almost equivalent, with one little difference: since Def uses an internal private object as lock, noone else can lock on that object from the outside world. In case of the Abc object, it is possible that someone else locks on the object then calls some of its methods from a different thread, which may result in deadlock. The practical possibility of this is faint (as it clearly requires some mischief or ignorance on another programmer's behalf), but is not zero. Therefore some people prefer the Def style to be on the safe side, although AFAIK the common idiom is as in Abc .

  2. Java locks are reentrant, so invoking a lock multiple times from the same thread is OK.

  3. Sorry, I am not competent on C#.

  4. Did you mean synchronized(this) instead of synchronized(lock) in the code example? Anyway, since show666 is not synchronized, calls to it do not block, even if another call to a synhronized method blocks on the same object.

see http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html

It should help you to answer 1 & 2, in particular it states:

Reentrant Synchronization

Recall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once enables reentrant synchronization. This describes a situation where synchronized code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock. Without reentrant synchronization, synchronized code would have to take many additional precautions to avoid having a thread cause itself to block.

  1. From that I understand that unless lock is synchronized by someone else, the two class are pretty much equivalent from the outside.

  2. Should not cause any particular problem thanks to Reentrant synchronization

(3. not familiar with C#)

1.Generally, they are different, since monitors of different objects are used in synchronized modules. BTW, these two classes will behave equivalently, if you will not use monitor of Abc class instances (particularly, if you will not use synchronized(abcObject){} outside abc class, where abcObject is an instance of Abc class)

2.a. The following two methods are equal:

public void add(int a)  {
    synchronized(this) {
         c += a;
    }
}

and

public synchronized void add(int a)  {
         c += a;
}

2.b. I don't see any problem in that code: two monitors (def instance's monitor and def.lock instance's monitor) are always locked in strict order (no circular wait condition)

3.Can't say anything about C#

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM