关于 Java 中的同步关键字(和 C# 的锁)的几个问题

发布于 2024-10-10 05:46:28 字数 1270 浏览 2 评论 0原文

  1. 以下类在 Java 中是否等效?如果不是,为什么?

    类 Abc {
        私有 int c = 0;
    
    
    
    public synchronized void add(int a) {
        c+=a;
    }
    
    
    公共同步无效减法(int a){
        c-=a;
    
    } } 类定义{ 私有 int c = 0; 私有最终对象锁=新对象();
    public void add(int a) {
        同步(锁){
             c+=a;
        }
    }
    
    
    公共无效减去(int a){
        同步(锁){
            c-=a;
        }
    
    } }
  2. 此外,在 Def 中使用 this 作为同步参数而不是 lock 会出现什么问题?是下面这个问题吗?

    Def def = new Def()
    同步(定义){
        def.add(5); //引发死锁?或者这是允许的
                    //因为所有这些都发生在同一个线程中?
    }
    
  3. Java中的synchronized语句和C#中的lock语句一样吗?如果不是,它们的区别是什么?如果是,为什么 C# 不像 Java 那样允许锁定方法?

  4. 所以我想 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) 它不需要任何与锁直接相关的信息。是这样吗?

  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;
    

    }
    }

    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;
        }
    

    }
    }

  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;
           }
    

    }

    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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

汹涌人海 2024-10-17 05:46:28

1 以下类在 Java 中是否等效?如果不是,为什么?

它们因同步的实例而异,因此受到这些实例之间差异的影响。

Abc 类使用调用该方法的 Abc 实例。有权访问该实例的其他代码也可以通过在同步块中显式使用该实例来使用它进行同步。

Def 类中的同步代码块显式命名与其同步的实例。由于此实例是 Def 实例私有的,因此 Def 外部的代码无法使用它进行同步(除非该实例以某种方式泄漏)。

有些人可能会认为 Def 方法更安全,封装锁很重要,就像您应该使用私有实例变量一样。

最后,synchronized关键字和使用synchronized语句之间有一些区别,例如synchronized语句可以锁定任何对象,而不仅仅是执行代码的实例,synchronized关键字稍微更高效等等。

2a 另外,在 Def 中使用它作为同步参数而不是锁会出现什么问题?

没问题。在实例方法上使用synchronized关键字在语义上与将该方法的代码包装在synchronized on this上的同步块中相同(synchronized关键字稍微更高效)。在静态方法上使用synchronized 关键字与在类本身上使用同步块synchronized 相同(例如synchronized(FooBar.class) { ... })。

2b 是以下问题吗?

不,Java 中的锁是可重入的,这意味着在保护实例上持有锁的线程可以进入和退出同一实例上同步的任何其他代码块。

3a Java 中的同步语句与 C# 中的锁定语句一样吗?如果不是,它们的区别是什么?

语义上是等价的。

http://en.csharp-online.net/CSharp_FAQ:_CSharp_lock_and_Java_synchronized#S之间的差异是什么同步代码块

但请注意这个关于 Monitor.EnterMonitor.Exit 的答案

Java 的“同步”和 C# 的“锁”之间有什么区别吗?

3b 如果是,为什么 C# 不像 Java 那样允许锁定方法?

它确实 - 使用 [MethodImpl(MethodImplOptions.Synchronized)] 注释。

http://en.csharp-online.net/CSharp_FAQ:_CSharp_lock_and_Java_synchronized#Syn chronized_methods

4 Thread1 调用 xyz.add(0),同时 Thread2 尝试调用 xyz.show666()。 Thread2 必须等待 Thread1 完成 xyz.add(0),尽管它不需要任何与锁直接相关的信息。是这样吗?

不,很多人认为“锁定”实例会影响整个实例。它仅影响在该实例上同步的同步代码(同步方法和同步语句中的代码)。未同步的代码不受影响(至少在它遇到同步语句或调用同步方法之前)。

非同步方法 show666() 不会导致线程阻塞。如果将 synchronized(this) 语句更改为 synchronized 方法,则不会发生任何变化 - 同样,show666 不会阻塞(除非它也是同步的)。

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, 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.

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 (e.g. 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).

屌丝范 2024-10-17 05:46:28
  1. 不,它们是不同的。使用 synchronized(reference){} 获取给定引用(您的锁对象)上的监视器锁,并在方法声明中使用 synchronized 使用 this用于监视器锁定。最终结果是外部调用者无法获得与 addsubtract 方法相同的锁。

  2. 不会出现死锁,您可以持有任意数量的监视器锁,而且 Def 对象使用不同的对象来锁定。但即使它是第一个类 Abc 它也不会死锁。 java中的同步锁是可重入的。因此,理论上您可以尝试将它们锁定在同一个线程上,次数不限。

  3. 令人惊讶的是,C# 不允许在方法上使用 lock,但在用于方法时,它似乎与 java synchronized 关键字相似(即使不相同)。一个参考。 C# 的设计目标之一是让 Java 开发人员足够熟悉,无需完全更换思维即可掌握它,所以我想这并不奇怪。

  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.

欢你一世 2024-10-17 05:46:28

请参阅http://download.oracle.com/javase/tutorial/essential/ concurrency/locksync.html

它应该可以帮助您回答 1 和 2 2,特别指出:

可重入同步

回想一下,线程无法获取
锁被另一个线程拥有。但一个
线程可以获取它的锁
已经拥有了。允许线程
多次获取同一个锁
启用可重入同步。
这描述了一种情况
同步代码,直接或
间接地调用一个方法,该方法也
包含同步代码,并且两者
多组代码使用相同的锁。
没有可重入同步,
同步代码必须采取
需要避免许多额外的预防措施
有一个线程会导致自身阻塞。

  1. 据此我了解到,除非锁被其他人同步,否则这两个类从外部来看几乎是等价的。

  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:

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#)

落墨 2024-10-17 05:46:28

1.一般来说,它们是不同的,因为同步模块中使用了不同对象的监视器。顺便说一句,如果您不使用 Abc 类实例的监视器(特别是,如果您不在 abc 类之外使用 synchronized(abcObject){},其中 abcObject 是 Abc 类的实例),这两个类的行为是等效的

。以下两种方法是相同的:

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

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

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:

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#

七秒鱼° 2024-10-17 05:46:28
  1. 它们几乎是等价的,只有一点点不同:由于 Def 使用内部私有对象作为锁,因此没有其他人可以从外部世界锁定该对象。对于 Abc 对象,其他人可能会锁定该对象,然后从不同的线程调用其某些方法,这可能会导致死锁。这种情况的实际可能性微乎其微(因为它显然需要代表另一个程序员进行一些恶作剧或无知),但并不为零。因此,为了安全起见,有些人更喜欢 Def 样式,尽管据我所知,常见的习惯用法是 Abc

  2. Java 锁是可重入的,因此从同一个线程多次调用锁是可以的。

  3. 抱歉,我不擅长 C#。

  4. 您是指代码示例中的 synchronized(this) 而不是 synchronized(lock) 吗?无论如何,由于 show666 未同步,因此对它的调用不会阻塞,即使对同一个对象上的同步方法的另一个调用阻塞。

  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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文