在Java中,可以同步访问多线程环境中所需的共享资源的方法或块。
我想知道“Scala Actors”这样做的方式是如何运作的。
假设我有一个java.sql.Connection
个对象的连接池,我希望提供对它的线程安全访问。我将它实现为接收消息并向发送者发回连接的actor。
似乎有三种方法可以做到这一点:
!?
Connection
的班级成为演员代码:
sealed abstract class ConnectionPoolMessage
case class NewConnection extends ConnectionPoolMessage
case class CloseConnection(c:Connection) extends ConnectionPoolMessage
class ConnectionPool extends Actor {
def act() {
while (true) {
receive() {
case NewConnection => sender ! getConnectionFromPool
case CloseConnection(conn) => returnConnection(conn)
}
}
}
}
// Here, my "do stuff" method is all in one place, and I block waiting
// on the Future from the pool; however this could take forever and cause trouble
class UsingFuture {
val pool = new ConnectionPool
def doSomething() {
val connectionFuture = pool !! NewConnection
val connection = connectionFuture() // concerned that we can't timeout here
// do stuff with my Connection instance
pool ! CloseConnection(connection)
}
}
// here, I wait and just use a timeout
// Seems clean to me, I guess.
class UsingBangQuestion {
val pool = new ConnectionPool
def doSomething() {
pool !?(TIMEOUT,NewConnection) match {
case Some(conn) => {
// do something with connection
pool ! CloseConnection(conn)
}
case None => throw new RuntimeException("timed out")
}
}
}
// here, I don't worry about timeouts, cause I only use the
// the connection when I receive a message back with it.
// The problem is that I now have to split my logic up
// with two methods
class AsAnActor extends Actor {
val pool = new ConnectionPool
def startSomething() {
start
pool ! NewConnection
}
def act() {
receive() {
case conn:Connection => finishSomething(conn)
}
}
def finishSomething(conn:Connection) {
// do stuff with my Connection
pool ! CloseConnection(conn)
}
}
未来版本似乎最干净,除了我可以永远阻止的事实。
任何想法,还是我对这个错误的全部概念?
答案 0 :(得分:2)
这可能是糟糕的风格,但一种方法是通过让您的actor(需要连接)直接插入连接池并使用同步来获取Connection
来混合命令式和功能性样式。说实话,我真的不明白这种方法有什么问题;我更喜欢!!
或!?
一个,只是尖叫死锁(甚至 livelock )!
我想另一种方法是向您的池发送一条消息,表示需要完成连接的工作以及结果的可能目标:
class DbWork(f: Connection => Unit)
class DbWorkWithResult[T](f:Connection => T, target: OutputChannel[Any])
然后你可以这样使用它:
pool ! new DbWork( { (conn: Connection) => //do something
})
或者:
pool ! new DbWorkWithResult[Int]( (conn: Connection) => //return int
}, self)
答案 1 :(得分:0)
Actors的做法不是共享资源。将所有访问权限提供给单个Actor,其作业是处理对共享资源的访问。
这样,资源本身不会在线程之间共享。演员是。
答案 2 :(得分:0)
如Scala actor to non-actor interaction (or synchronizing messages from an actor to a servlet)的答案所示,如果超时,您可以使用!?(超时,消息)接收部分(答案)或无。