2013-05-11 126 views
1

我的應用程序有一個ApplicationUsers類,它沒有可變成員。在創建實例後,它將整個用戶數據庫(相對較小)讀入一個不可變的集合中。它有很多方法來查詢數據。共享變種可以安全嗎?

我現在面臨着必須創建新用戶(或修改其某些屬性)的問題。我目前的想法是使用一個Akka演員,在高層次,看起來像這樣:

class UserActor extends Actor{ 
    var users = new ApplicationUsers 

    def receive = { 
    case GetUsers => sender ! users 

    case SomeMutableOperation => { 
     PerformTheChangeOnTheDatabase() // does not alter users (which is immutable) 
     users = new ApplicationUsers // reads the database from scratch into a new immutable instance 
    } 
    } 
} 

這是安全嗎?我的推理是:它應該是:users每當更改SomeMutableOperation任何其他線程利用以前的users實例已經有一個老版本的句柄,不應該受到影響。此外,任何GetUsers請求將不會被採取行動,直到新的實例不安全構建。

有什麼我失蹤?我的構造是否安全?

更新:我可能應該使用Agents來做到這一點,但問題仍然存在:上述安全嗎?

回答

3

您正在做的完全正確:擁有不可變的數據類型,並通過演員中的var引用它們。這樣你就可以自由分享數據,可變性僅限於演員。唯一需要注意的是,如果您從在演員之外執行的閉包中引用var(例如在Future轉換或Props實例中)。在這種情況下,你需要做一個堆棧的本地副本:

val currentUsers = users 
other ? Process(users) recoverWith { case _ => backup ? Process(currentUsers) } 

在第一種情況下,你只要抓住價值,這是很好的,但要求backup從不同的線程發生,因此需要爲val currentUsers

1

對我來說很好。你在這裏似乎不需要代理。

+0

謝謝。我認爲代理會簡化我的代碼(不需要創建上面的構造),並且自然會將數據庫的更新與'用戶'對象的更新分離開來,這在我的情況下會是更好的設計。 – Eduardo 2013-05-11 07:53:47

+0

我認爲代理的問題在於它們只對您運行的節點(jvm)是本地的。您無法將它們遠程傳遞給其他節點。當你想擴展你的系統時,這可能會產生問題。 – Bacon 2015-08-19 15:54:58