10

在 Java 中,可以同步访问多线程环境中所需的共享资源的方法或块。

我想知道这样做的“Scala Actors”方式是如何工作的。

假设我有一个java.sql.Connection我希望提供线程安全访问的对象连接池。我将它实现为一个接收消息并向发送者发送回连接的参与者。

似乎有三种方法可以做到这一点:

  1. 使用未来
  2. 利用!?
  3. 有需要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)
  }
}

未来版本似乎最干净,除了我可以永远阻止的事实。

有什么想法,或者我对此的整个概念是错误的吗?

4

3 回答 3

2

这可能是不好的风格,但一种方法是混合命令式和函数式风格,让你的演员(需要连接)直接插入连接池并使用同步来获得Connection. 老实说,我真的不明白这种方法有什么问题。我更喜欢它而不是!!or !?,它只是尖叫死锁(甚至是活锁)!

我想另一种方法是向您的池发送一条消息,该消息表示需要通过连接完成的工作以及结果的可能目标:

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)
于 2009-10-29T19:49:44.107 回答
0

Actors 的做法不是共享资源。将所有访问权提供给单个 Actor,该 Actor 的工作是处理对共享资源的访问。

这样,资源本身就不会在线程之间共享。演员是。

于 2009-10-29T21:07:06.930 回答
0

正如对Scala 演员与非演员交互(或将消息从演员同步到 servlet)的答案中所见,您可以使用 !?(timeout, message) 来接收 Some(answer) 或 None 如果超时。

于 2011-01-11T10:00:49.957 回答