Java 在将来的代码中使用同步/锁定
我们正在使用Scala、Play framework和MongoDB(使用ReactiveMongo作为驱动程序)构建一个web应用程序。应用程序体系结构是端到端非阻塞的 在代码的某些部分,我们需要访问一些非线程安全的库,如Scala的解析器组合器、Scala的反射等。我们目前将此类调用封装在Java 在将来的代码中使用同步/锁定,java,scala,concurrency,playframework-2.0,akka,Java,Scala,Concurrency,Playframework 2.0,Akka,我们正在使用Scala、Play framework和MongoDB(使用ReactiveMongo作为驱动程序)构建一个web应用程序。应用程序体系结构是端到端非阻塞的 在代码的某些部分,我们需要访问一些非线程安全的库,如Scala的解析器组合器、Scala的反射等。我们目前将此类调用封装在synchronized块中。我有两个问题: 将synchronized与future-y代码一起使用时,是否有需要注意的问题 从性能和可用性的角度来看,使用锁(例如ReentrantLock)比使用syn
synchronized
块中。我有两个问题:
synchronized
与future-y代码一起使用时,是否有需要注意的问题ReentrantLock
)比使用synchronized
)更好吗您提到的示例(即反射和解析)应该是不可变的,不需要锁定,但是如果要使用锁定,则可以使用同步块。我认为使用synchronized与Lock之间的性能差别不大。这是一个老问题)例如,请参见此处。简言之,最好使用参与者而不是锁:
class GreetingActor extends Actor with ActorLogging {
def receive = {
case Greeting(who) ⇒ log.info("Hello " + who)
}
}
在任何给定的时间只处理一条消息,所以您可以将任何不安全的代码放在log.info中,而不是放在log.info中,一切正常。顺便说一句,使用ask模式,您可以将参与者无缝地集成到需要未来的现有代码中。对我来说,您将面临的主要问题是,对同步或锁定代码段的任何调用都可能会阻塞,从而使执行上下文的线程瘫痪。为了避免此问题,您可以使用
scala.concurrent.blocking
包装对潜在阻塞方法的任何调用:
import scala.concurrent._
import ExecutionContext.Implicits.global
def synchronizedMethod(s: String) = synchronized{ s.size }
val f = future{
println("Hello")
val i = blocking{ //Adjust the execution context behavior
synchronizedMethod("Hello")
}
println(i)
i
}
当然,最好考虑诸如线程局部变量之类的替代方案或者将调用封装到一个行动者中的串行代码中。
最后,我建议使用synchronized而不是锁。对于大多数应用程序(特别是在关键部分很大的情况下),性能差异并不明显。我认为最简单、最安全的方法是(如果可以的话)使用线程限制。 i、 每个线程创建自己的解析器组合器实例等,然后使用它
如果您需要任何同步(应该避免,因为在流量不足的情况下,它将是杀手),
synchornized
或ReentrantLock
将提供几乎相同的性能。这同样取决于需要保护哪些对象以及哪些锁等。在web应用程序中,除非绝对必要,否则不建议这样做。我很难理解您所说的“未来代码”@fge是什么意思,因为代码大量使用了未来
s。我认为从上下文(Play、Reactive*等)来看这已经足够清楚了,但似乎不是这样,所以很抱歉,您不应该使用默认的执行上下文执行阻塞操作。可能有用。+1用于阻塞()提示。同意使用synchronized
,除非你想利用锁轮询、超时、可中断性等。你能提供更多关于如何实现线程限制的信息吗?你能详细说明什么是“ask模式”以及如何使用它吗?我不能比官方文档做得更好