关于 Java 中的同步关键字(和 C# 的锁)的几个问题
以下类在 Java 中是否等效?如果不是,为什么?
类 Abc { 私有 int c = 0;
} } 类定义{ 私有 int c = 0; 私有最终对象锁=新对象();public synchronized void add(int a) { c+=a; } 公共同步无效减法(int a){ c-=a;
} }public void add(int a) { 同步(锁){ c+=a; } } 公共无效减去(int a){ 同步(锁){ c-=a; }
此外,在
Def
中使用this
作为同步参数而不是lock
会出现什么问题?是下面这个问题吗?Def def = new Def() 同步(定义){ def.add(5); //引发死锁?或者这是允许的 //因为所有这些都发生在同一个线程中? }
Java中的synchronized语句和C#中的lock语句一样吗?如果不是,它们的区别是什么?如果是,为什么 C# 不像 Java 那样允许锁定方法?
所以我想
synchronized (this)
的问题可以通过以下示例来描述?类 Xyz { 私有 int c;
}public void add(int a) { 同步(这个){ c+=a; } } 公共无效减去(int a){ 同步(这个){ c-=a; } } 公共无效show666(){ 返回666; }
Thread1 调用
xyz.add(0)
,同时 Thread2 尝试调用xyz.show666()
。 尽管如此,线程 2 仍必须等待线程 1 完成xyz.add(0)
它不需要任何与锁直接相关的信息。是这样吗?
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;
}
}class Def {
private int c = 0;
private final Object lock = new Object();public void add(int a) { synchronized(lock) { c += a; } } public void subtract(int a) { synchronized(lock) { c -= a; }
}
}
Also, what would be the problem of in
Def
, usingthis
as synchronized parameter instead oflock
? 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? }
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?
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; }
}
Thread1 calls
xyz.add(0)
and at the same time Thread2 tries to callxyz.show666()
.
Thread2 has to wait for Thread1 to finish withxyz.add(0)
althtough
it doesn't need any info directly related with the lock. Is that it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
它们因同步的实例而异,因此受到这些实例之间差异的影响。
Abc
类使用调用该方法的Abc
实例。有权访问该实例的其他代码也可以通过在同步块中显式使用该实例来使用它进行同步。Def
类中的同步代码块显式命名与其同步的实例。由于此实例是Def
实例私有的,因此Def
外部的代码无法使用它进行同步(除非该实例以某种方式泄漏)。有些人可能会认为
Def
方法更安全,封装锁很重要,就像您应该使用私有实例变量一样。最后,synchronized关键字和使用synchronized语句之间有一些区别,例如synchronized语句可以锁定任何对象,而不仅仅是执行代码的实例,synchronized关键字稍微更高效等等。
没问题。在实例方法上使用synchronized关键字在语义上与将该方法的代码包装在synchronized on
this
上的同步块中相同(synchronized关键字稍微更高效)。在静态方法上使用synchronized 关键字与在类本身上使用同步块synchronized 相同(例如synchronized(FooBar.class) { ... }
)。不,Java 中的锁是可重入的,这意味着在保护实例上持有锁的线程可以进入和退出同一实例上同步的任何其他代码块。
语义上是等价的。
http://en.csharp-online.net/CSharp_FAQ:_CSharp_lock_and_Java_synchronized#S之间的差异是什么同步代码块
但请注意这个关于
Monitor.Enter
和Monitor.Exit
的答案Java 的“同步”和 C# 的“锁”之间有什么区别吗?
它确实 - 使用
[MethodImpl(MethodImplOptions.Synchronized)]
注释。http://en.csharp-online.net/CSharp_FAQ:_CSharp_lock_and_Java_synchronized#Syn chronized_methods
不,很多人认为“锁定”实例会影响整个实例。它仅影响在该实例上同步的同步代码(同步方法和同步语句中的代码)。未同步的代码不受影响(至少在它遇到同步语句或调用同步方法之前)。
非同步方法
show666()
不会导致线程阻塞。如果将synchronized(this)
语句更改为synchronized
方法,则不会发生任何变化 - 同样,show666
不会阻塞(除非它也是同步的)。They differ by what instance they synchronize on and thus are affected by the differences between those instances.
Class
Abc
uses theAbc
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 theDef
instance, code external toDef
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, e.g. the synchronized statement can lock on any object, not just the instance of the executing code, the synchronize keyword is slightly more efficient, etc.
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 (e.g.synchronized(FooBar.class) { ... }
).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.
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
andMonitor.Exit
Are there any differences between Java's "synchronized" and C#'s "lock"?
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
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 thesynchronized(this)
statements were changed intosynchronized
methods - againshow666
won't block (unless its synchronized too).不,它们是不同的。使用
synchronized(reference){}
获取给定引用(您的锁对象)上的监视器锁,并在方法声明中使用synchronized
使用this
用于监视器锁定。最终结果是外部调用者无法获得与add
和subtract
方法相同的锁。不会出现死锁,您可以持有任意数量的监视器锁,而且
Def
对象使用不同的对象来锁定。但即使它是第一个类Abc
它也不会死锁。 java中的同步锁是可重入的。因此,理论上您可以尝试将它们锁定在同一个线程上,次数不限。令人惊讶的是,C# 不允许在方法上使用
lock
,但在用于方法时,它似乎与 javasynchronized
关键字相似(即使不相同)。一个参考。 C# 的设计目标之一是让 Java 开发人员足够熟悉,无需完全更换思维即可掌握它,所以我想这并不奇怪。No they are different. using
synchronized(reference){}
obtains the monitor lock on the given reference (your lock object) and usingsynchronized
in a method declaration usesthis
for the monitor lock. The net result is that an exteral caller can't obtain the same lock as theadd
andsubtract
methods.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 classAbc
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.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 javasynchronized
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.请参阅http://download.oracle.com/javase/tutorial/essential/ concurrency/locksync.html
它应该可以帮助您回答 1 和 2 2,特别指出:
据此我了解到,除非锁被其他人同步,否则这两个类从外部来看几乎是等价的。
由于可重入同步,不应导致任何特定问题
(3. 不熟悉 C#)
see http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html
It should help you to answer 1 & 2, in particular it states:
From that I understand that unless lock is synchronized by someone else, the two class are pretty much equivalent from the outside.
Should not cause any particular problem thanks to Reentrant synchronization
(3. not familiar with C#)
1.一般来说,它们是不同的,因为同步模块中使用了不同对象的监视器。顺便说一句,如果您不使用 Abc 类实例的监视器(特别是,如果您不在 abc 类之外使用 synchronized(abcObject){},其中 abcObject 是 Abc 类的实例),这两个类的行为是等效的
。以下两种方法是相同的:
和
2.b。我在该代码中没有看到任何问题:两个监视器(def实例的监视器和def.lock实例的监视器)始终以严格的顺序锁定(无循环等待条件)
3.不能说任何关于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:
and
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#
它们几乎是等价的,只有一点点不同:由于
Def
使用内部私有对象作为锁,因此没有其他人可以从外部世界锁定该对象。对于Abc
对象,其他人可能会锁定该对象,然后从不同的线程调用其某些方法,这可能会导致死锁。这种情况的实际可能性微乎其微(因为它显然需要代表另一个程序员进行一些恶作剧或无知),但并不为零。因此,为了安全起见,有些人更喜欢Def
样式,尽管据我所知,常见的习惯用法是Abc
。Java 锁是可重入的,因此从同一个线程多次调用锁是可以的。
抱歉,我不擅长 C#。
您是指代码示例中的
synchronized(this)
而不是synchronized(lock)
吗?无论如何,由于show666
未同步,因此对它的调用不会阻塞,即使对同一个对象上的同步方法的另一个调用阻塞。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 theAbc
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 theDef
style to be on the safe side, although AFAIK the common idiom is as inAbc
.Java locks are reentrant, so invoking a lock multiple times from the same thread is OK.
Sorry, I am not competent on C#.
Did you mean
synchronized(this)
instead ofsynchronized(lock)
in the code example? Anyway, sinceshow666
is not synchronized, calls to it do not block, even if another call to a synhronized method blocks on the same object.