Java 我应该在Scala中同步哪个对象?
在C#中,这非常简单:Java 我应该在Scala中同步哪个对象?,java,multithreading,scala,Java,Multithreading,Scala,在C#中,这非常简单: class Class1{ private static readonly object locker = new object(); void Method1(){ lock(locker) { .... } } } 我绝对不应该对这个进行同步,因为这可能会导致死锁。类似地,在Scala中,我看到了一些示例,但无法理解同步的基本原理以及我应该使用的对象(字段)来进行同步: #1 def add(user: User) { // tokenize
class Class1{
private static readonly object locker = new object();
void Method1(){
lock(locker) { .... }
}
}
我绝对不应该对这个进行同步,因为这可能会导致死锁。类似地,在Scala中,我看到了一些示例,但无法理解同步的基本原理以及我应该使用的对象(字段)来进行同步:
#1
def add(user: User) {
// tokenizeName was measured to be the most expensive operation.
val tokens = tokenizeName(user.name)
tokens.foreach { term =>
userMap.synchronized {
add(term, user)
}
}
}
#2
class Person(var name: String) {
def set(changedName: String) {
this.synchronized {
name = changedName
}
}
}
#3 and so on...
你能帮我说清楚吗
在Scala中锁定对象与在Java中锁定静态字段/类是一样的,这基本上是“最难”的锁定之一。它不会阻止类实例上的操作,而是阻止类加载器范围内的类本身上的操作。在引入这样的锁时,您应该仔细考虑。它不会保护您免受由于获取的锁的顺序不正确而导致的死锁的影响,但是如果线程正在处理一个类的不同实例,则会导致阻塞线程,并且可能根本不会产生干扰
锁定“this”或某个类(非对象)字段(互斥)是一种更轻松的同步方式,您应该使用它来管理对该类的访问,而不是对该类的特定实例的访问
看一看电影中的演员,他们摇摆不定,消除了许多同步方面的问题
旁注:对“this”进行同步并不意味着死锁。在Scala中,获得相同的行为更为简单(我假设您出于某种原因希望锁定包含的对象,例如,比锁定该类的整个实例更细粒度的控制):
但你不应该以这种方式控制事情。特别是,如果不注意…
,它将无法防止C#或Scala中的死锁
您至少应该使用java.util.concurrent
中的并发工具,并且您可能希望了解未来或参与者。如果前提是您希望避免锁定此
,因为另一个具有第三方代码的线程可以锁定同一对象,那么Scala提供了更高级别的可见性私有[这]
class C {
private[this] val lock = new Object()
def method1(): Unit = lock.synchronized {
println("method1")
}
}
实际上,除了C
的特定实例之外,没有其他对象可以访问lock
。即使来自同一类的其他实例也无法访问lock
,在“this”上进行同步并不意味着死锁。
在Java中?在C中可能是这样。我不确定如何在类I上进行同步nstance单独会导致死锁。如果您在线程B中锁定实例A,然后尝试锁定实例C,在线程D中锁定实例C并尝试锁定实例A,那么不管对象A和C是什么(静态还是非静态),您都会遇到麻烦.对“this”进行同步并不意味着死锁。--在Java中?在C中,这可能是肯定的。我认为#1中的单词选择不仔细(即,错误).Scala对象类似于Java静态,但它只是一个普通的引擎盖下的实例,一个类似Foo$.MODULE$.Foo.synchronized的静态字段意味着在该实例上进行同步,而不是在Foo$.class上进行同步。我不知道C#,但在上进行同步这
不会自动在Java或Scala.I中引入死锁风险t取决于您对它们所做的操作当另一个线程在实例B和实例A上进行同步时,您就遇到麻烦了。虽然在scala中可以进行同步,但消除对它的需要会更为习惯。例如,使用不可变的数据结构,并以允许非阻塞异步执行的方式设计程序。@Romptroll,我对它很好奇。您可以吗请给我举个例子?但尽管如此,即使使用不可变的数据结构也只是将同步的责任进一步转移,例如,对于将使用不可变状态的代码的人,最终也将有必要使用它。据我所知,即使使用synchronized
方法,也无法避免使用synchronized
方法当只有不可变的数据结构时。不是吗?如果你的程序没有分叉,为什么你需要同步的?如果你的子例程都基于不可变的结构,唯一可以看到状态更新的地方就是你的主方法。你可以完美地设计大型库,而不需要引入一个系统nchronized
关键字。@Grienders,不,完全可能。如果您的数据完全不可变(没有例外;这也意味着没有执行I/O操作),则实际上不需要显式同步,因为没有线程能够以任何方式干扰其他线程操作。但是,对于不可变数据,线程之间传输数据的唯一方法是使用新数据段启动新的子线程。这可能非常不方便且无效,因此最终您只需具有可变状态。但是不同的库尝试抽象此状态,因此您不会直接访问它,因此您仍然不需要同步
。例如,这就是actor库(例如Akka)的功能在较低的级别上,每个参与者都有可变的消息队列,但您不直接访问它,而是使用不可变的消息。因此,您的代码中没有同步的消息。@Grienders这是Scala,而且确实是创建私有锁的正确方法,它减少了死锁的风险,因为Class1
完全控制了死锁的位置使用了锁。如果您只有一个私有锁,则不会陷入死锁。对于潜在的死锁,您至少需要两个锁。@Grienders-这就是Scala。您说过“在C中,这非常简单”。我更简单地演示了如何在Scala中执行完全相同的操作。因此,如果您已经知道如何在C#中执行此操作,那么现在您就知道如何在Scala中执行此操作。@0#-您确实需要至少两个锁,但它们可以是同一类的不同实例上的两个锁。因此,即使使用单个私有锁,您也必须非常小心。T
class C {
private[this] val lock = new Object()
def method1(): Unit = lock.synchronized {
println("method1")
}
}