【问题标题】:Java-like thread synchronization in C#C# 中的类 Java 线程同步
【发布时间】:2009-10-26 15:03:07
【问题描述】:

我是一名 Java 程序员,我知道一些关于线程 int Java 的知识。

在 Java 中我可以使用 synchronized 关键字来锁定一个方法:

private int a;
private int b;
private int c;
private synchronized void changeVars()
{
  a = 4;
  b = 2;
  c = a+b;
}

我在msdn中搜索,发现c#中有一些玩具可以玩线程。比如monitor.Enter、monitor.Exit、lock或者一个高级的互斥锁。

但我需要的是同步一种方法。在c#中它的等价物是什么?

提前致谢。

【问题讨论】:

    标签: c# java multithreading thread-safety


    【解决方案1】:

    在 C# 中没有直接的等价物,但你可以用这个做同样的事情:

    private readonly object changeVarsLockObject = new object();
    
    private void changeVars()
    {
      lock(changeVarsLockObject)
      {
        a = 4;
        b = 2;
        c = a+b;
      }
    }
    

    【讨论】:

    • 不是该语言;我最好说 C# 中没有等效的关键字,但你可以编写代码来做同样的事情。
    【解决方案2】:

    可能是这样的:

    using System.Runtime.CompilerServices;
    
    ...
    
    private int a;
    private int b;
    private int c;
    
    [MethodImpl(MethodImplOptions.Synchronized)]
    private void changeVars()
    {
      a = 4;
      b = 2;
      c = a+b;
    }
    

    【讨论】:

    • 我可能应该在正文中提到我在发布后不久修改了这个答案;我认为 MethodImpl 是比 lock(this) 更好的选择,因为它可以让编译器选择最佳方法。
    • 可能值得一提的是 MethodImplOption.Synchronized 和 lock(this) 不再建议作为编写线程安全方法的方法,因为它们会产生死锁机会。以下博客有更多详细信息:blogs.msdn.com/bclteam/archive/2004/01/20/60719.aspx
    【解决方案3】:

    要明确一点——在 Java 中声明同步的方法要求调用者将监视器保存在调用该方法的 对象 上(静态方法是 Class 对象)。

    所以说你可以“锁定一个方法”是一种误导,因为你没有完全锁定那个方法(同样的方法仍然可以在不同的实例对象上调用),而且你锁定的更多方法(任何其他需要目标对象监视器的代码,包括其他同步方法或显式获取它,都不能同时运行)。

    同步很难,理想情况下,如果您想避免在测试期间几乎不会出现的死锁和可见性问题,或者有利于调试,那么您需要了解的不仅仅是“一些事情” .对一种语言中的同步可能不完全理解,并试图将其转移到另一种具有不同原语和可能不同内存模型的语言中,这将导致灾难。

    因此,虽然这不是您要寻找的单行答案,但我要断言,如果没有整个生态系统的知识来支持,任何单行答案都注定会失败。因此,您应该阅读一本关于 C# 同步的好书/教程,而不是尝试逐个关键字翻译您的 Java 体验。

    【讨论】:

    • “因此,您应该阅读一本关于 C# 同步的好书/教程,而不是尝试逐个关键字翻译您的 Java 经验。”等等,你是不是在暗示这在某种程度上也不是 Java 的问题?
    • +1 不知道 synchronized 关键字。是否可以从对象外部获取等效锁?
    • @FacticiusVir,您可以使用同步(实例)来获取与 Java 在输入声明为该实例上同步的方法时所获取的相同的锁(或显式使用 Monitor 方法)。跨度>
    • @Freed 不,我得到的 C#/.NET 代码,因为我使用 .NET 同步结构做了很多工作;这是我不熟悉的Java代码。这就是我问这个问题的原因;如果 Java 中没有等效于 C# 中的 lock(instance) 的方法,那么 Java 中的“同步”和 C# 中的“lock(this)”之间存在重要区别。
    • @FacticiusVir, synchronized 关键字可以在 Java 中的块级别使用,就像 C# 中的 lock 关键字一样,并且方法上的同步确实使用对象实例,或者如果使用在类实例上静态方法。此答案中没有任何内容与此相矛盾,dtsazza 只是指出它不是被锁定的 方法
    【解决方案4】:

    直接等价于使用锁(this):

    private void ChangeVars()
    {
        lock (this) {
            a = 4;
            b = 2;
            c = a+b;
        }
    }
    

    或者确实使用 R. Bemrose 描述的 MethodImplAttribute,这相当于同一件事:

    [MethodImpl(MethodImplOptions.Synchronized)]
    private void ChangeVars()
    {
        a = 4;
        b = 2;
        c = a+b;
    }
    

    ...但是,不建议使用公开可见的对象进行锁定,因为其他人可能也决定将其用作锁定对象,因此更好的翻译是:

    private object monitor = new object();
    private void ChangeVars()
    {
        lock (monitor) {
            a = 4;
            b = 2;
            c = a+b;
        }
    }
    

    【讨论】:

      【解决方案5】:

      首选的解决方案是将方法体包装在 lock 语句中。

      internal class Foo
      {
         private Object lockObject = new Object();
      
         private void ChangeVars()
         {
            lock (this.lockObject)
            {
               // Manipulate the state.
            }
         }
      }
      

      您也可以使用声明式同步,但这有一个明显的缺点,即您必须从ContextBoundObject 派生,并且所有使用Synchronization 属性修饰的方法共享相同的锁定对象,从而限制了锁定粒度。

      internal class Foo : ContextBoundObject
      {
         [Synchronization]
         private void ChangeVars()
         {
            // Manipulate the state.
         }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-01
        • 2011-01-16
        • 1970-01-01
        • 1970-01-01
        • 2012-02-25
        • 1970-01-01
        相关资源
        最近更新 更多