Java同步关键字的C#版本?


313

c#是否具有自己的java“ synchronized”关键字版本?

即在Java中,可以将其指定为函数,对象或代码块,如下所示:

public synchronized void doImportantStuff() {
   // dangerous code goes here.
}

要么

public void doImportantStuff() {
   // trivial stuff

   synchronized(someLock) {
      // dangerous code goes here.
   }
}

3
块形式需要引用来锁定。在方法形式中,锁定对象是隐式的(或者对于静态方法,是Class [this.class,不是getClass()],但不要锁定Classes)。
Tom Hawtin-大头钉

1
仍然不受保护?我总是来这里,因为我不记得那条[MethodImpl(MethodImplOptions.Synchronized)]线。
Bitterblue 2014年

1
我认为您的第二个代码段无法编译-需要在某些内容上进行同步
PoweredByRice 2015年

Answers:


466

首先-大多数类将永远不需要是线程安全的。使用YAGNI:仅当您知道实际上将要使用它(并对其进行测试)时,才应用线程安全性。

对于方法级的东西,有[MethodImpl]

[MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */}

这也可以用于访问器(属性和事件):

private int i;
public int SomeProperty
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    get { return i; }
    [MethodImpl(MethodImplOptions.Synchronized)]
    set { i = value; }
}

请注意,默认情况下,类似字段的事件同步的,而自动实现的属性则不是

public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized

就我个人而言,我不喜欢使用MethodImplthistypeof(Foo)-这是违反最佳做法的实现。首选选项是使用您自己的锁:

private readonly object syncLock = new object();
public void SomeMethod() {
    lock(syncLock) { /* code */ }
}

请注意,对于类似字段的事件,锁定实现取决于编译器。在较旧的Microsoft编译器中,它是lock(this)/ lock(Type)-但是,在较新的编译器中,它使用Interlocked更新-因此具有线程安全性而没有令人讨厌的部分。

这允许更精细的使用,并允许使用Monitor.Wait/ Monitor.Pulseetc在线程之间进行通信。

相关的博客条目(后来重新访问)。


@earcam,您的问题是?那句话是真的。绝大多数类都不需要是线程安全的,不会经过线程安全测试,而拥有线程安全会影响性能。真正需要担心线程的类型数量非常少-有意同步的集合,多路复用器等
Marc Gravell

4
我想我应该简单地说一下;“大多数类永远都不需要是线程安全的”,而是“所有开发人员必须知道并发性”。回想起来,我同意这个数目很小(绝对是您希望一次在某处得到正确处理的东西,它允许大多数类交互而不考虑其多线程环境)。希望我能更快删除评论=)
earcam

6
Marc的链接博客文章2010年3月作了跟踪报道,说在.NET 4.0中,MethodImpl类似字段的事件现在可以生成良好的同步代码,不再需要使用您自己的锁。
罗里·奥肯

2
如今,大多数应用程序都是基于Web的,并具有依赖于大量实例重用和依赖注入的复杂对象生命周期的框架。这些天的默认思维定势倾向于错误的线程安全性。
羊皮的

1
@Elazar现在为时已晚,但请注意:更改框架是对csproj的单行更改,如果您使用.net standard / .net核心模板创建了它-则可以使用常规.net。 -定位。但是,围绕这件事的IDE工具简直太糟糕了-您只需要知道可以更改的内容和内容即可:)
Marc Gravell

57
static object Lock = new object();

lock (Lock) 
{
// do stuff
}

9
您确定要将锁定对象声明为static ..?
serg10

21
当然,每个线程都可以轻松访问它,而无需传递引用。
Jan Gressmann

32
如果我们处于询问者问题的上下文中,那么我们正在谈论实例方法。使用静态意味着如果线程1调用instance1.DoSomething(),而线程2调用instance2.DoSomething,则第二个调用将阻塞,即使它是一个完全不同的对象。除非有人在同一对象上调用DoSomething,否则thread2的调用不应阻塞。并不是说您错了,而是说在这里了解使用static的效果很重要,因为它可能会因全局阻塞而不是按实例阻塞而导致性能下降。
AaronLS

1
@AaronLS当对象在比其自身更大的作用域上执行操作时,静态锁(如果非常有用)。例如,总是发生在Web服务上。
Thibault D.

3
-1,因为这与OP要求的行为不同。这是一个类锁,而不是实例锁。
tster

39

c#是否具有自己的java“ synchronized”关键字版本?

否。在C#中,您显式地指定lock了要在异步线程之间同步工作的资源。lock打开一个块;它在方法级别上不起作用。

但是,底层机制是相似的,因为它lock是通过在运行时调用Monitor.Enter(并随后Monitor.Exit)进行工作的。根据Sun文档,Java的工作方式相同。


3
它没有等效的“关键字”,但是正如上文Marc Gravell的答案所示,您可以使用[MethodImpl(MethodImplOptions.Synchronized)]批注在方法级别进行同步。
MindJuice 2013年

1
由于Java的synchronizedon方法基本上synchronized (this.getClass())在C#上不会类似lock(typeof(this))
Sri Harsha Chilakapati'4

2
@SriHarshaChilakapati只是部分正确,synchronized方法上的java 关键字更像::synchronized(this),仅在静态方法上表现为synchronized(class)
bvdb '18

7

请注意,使用完整路径的行:[MethodImpl(MethodImplOptions.Synchronized)]应该看起来像

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]


1
或者您也可以使用using System.Runtime.CompilerServices;
aloisdg移至codidact.com

在对C#进行了几天或几周的编程之后,我还不知道如何使用using语句自动插入时,我写了该评论,我对这3项投票感到惊讶。
Traubenfuchs 2015年

1
您帮助了至少3个开发人员,这很好:)
aloisdg移至codidact.com

5

您可以lock改为使用该语句。我认为这只能替代第二个版本。此外,请记住,这两个synchronizedlock有需要的对象进行操作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.