2017-05-31 41 views
0

我在我的系統,並根據事件和上次計算值計算值的功能活動:如何更改此實現以使用單個同步塊而不是多個?

當我把這個功能我想這種行爲:

  • 如果有新的事件,它應該使用事件和去年memoized值計算新值,memoize的結果
  • 如果沒有新的事件,它應該返回memoized

這裏最後的值執行我CA我與:

<!-- language: lang-scala --> 
class EventBasedMemo[Value, Event](initialValue: => Value, 
            buildValue: (Value, Event) => Value, 
            nextEvent: Option[Event] = None) { 

    lazy val memoValue: Value = 
    nextEvent.fold(initialValue)(event => buildValue(initialValue, event)) 

    def update(event: Event): EventBasedMemo[Value, Event] = 
    new EventBasedMemo(memoValue, buildValue, Option(event)) 

} 

type Value = Int 
type Event = String 
var callsCount = 0 

var memo = new EventBasedMemo[Value, Event](0, (value, event) => { 
    callsCount += 1 
    println(s"$callsCount $event") 
    value + 1 
}) 

memo = memo.update("A") 
memo = memo.update("B") 
memo = memo.update("C") 

memo.memoValue // 1 A 2 B 3 C 
memo.memoValue 

memo = memo.update("D") 

memo.memoValue // 4 D 

這工作正常。但問題是lazy val在引擎蓋下使用同步,所以有多個嵌套同步發生在計算上,這是不好的。

如何更改它以便它只使用一個同步?

我想解決方案是不可變的。

回答

0

使用手動記憶可以避免同步塊。但是在多線程場景中,緩存可能會重新計算多次。只有在計算沒有副作用時才重新計算它是安全的(例如沒有打印語句)。

class EventBasedMemo[Value, Event](initialValue: => Value, 
            buildValue: (Value, Event) => Value, 
            nextEvent: Option[Event] = None) { 

    var cache: Option[Value] = None 

    def memoValue(): Value = { 
    cache match { 
     case None => 
     cache = Some(nextEvent.fold(initialValue)(event => buildValue(initialValue, event))) 
     cache.get 
     case Some(value) => value 
    } 
    } 

    def update(event: Event): EventBasedMemo[Value, Event] = 
    new EventBasedMemo(memoValue, buildValue, Option(event)) 

} 

如果你真的想快速同步懶值,那麼就來看看讀/寫鎖像ReentrantReadWriteLock。接下來的代碼只是演示,不確定它在多線程環境中正常工作。

import java.util.concurrent.locks.ReentrantReadWriteLock 

class EventBasedMemo[Value, Event](initialValue: => Value, 
            buildValue: (Value, Event) => Value, 
            nextEvent: Option[Event] = None, 
            lock:ReentrantReadWriteLock = new ReentrantReadWriteLock()) { 

    var cache: Option[Value] = None 

    def memoValue(): Value = { 
    lock.readLock().lock() 
    val result = cache match { 
     case None => 
     lock.readLock().unlock() 
     lock.writeLock().lock() 
     cache = Some(nextEvent.fold(initialValue)(event => buildValue(initialValue, event))) 
     lock.writeLock().unlock() 
     lock.readLock().lock() 
     cache.get 
     case Some(value) => value 
    } 
    lock.readLock().unlock() 
    result 
    } 

    def update(event: Event): EventBasedMemo[Value, Event] = 
    new EventBasedMemo(memoValue, buildValue, Option(event), lock) 

} 
相關問題