Swift 實現(xiàn)線程安全的LRU


final class UnfairLock: NSLocking {
    let unfairLock: NSLocking
    
    init() {
        if #available(iOS 16.0, *) {
            unfairLock = AllocatedUnfairLock()
        } else {
            unfairLock = OSUnfairLock()
        }
    }
    
    func lock() {
        unfairLock.lock()
    }
    
    func unlock() {
        unfairLock.unlock()
    }
    
    @available(iOS 16.0, *)
    private final class AllocatedUnfairLock: NSLocking {
        private let allocUnfairLock = OSAllocatedUnfairLock()
        
        func lock() {
            allocUnfairLock.lock()
        }
        
        func unlock() {
            allocUnfairLock.unlock()
        }
    }
    
    private final class OSUnfairLock: NSLocking {
        
        private let osUnfairLock: os_unfair_lock_t
        
        init() {
            osUnfairLock = .allocate(capacity: 1)
            osUnfairLock.initialize(to: os_unfair_lock())
        }
        
        deinit {
            osUnfairLock.deinitialize(count: 1)
            osUnfairLock.deallocate()
        }
        
        func lock() {
            os_unfair_lock_lock(osUnfairLock)
        }
        
        func tryLock() -> Bool {
            return os_unfair_lock_trylock(osUnfairLock)
        }
        
        func unlock() {
            os_unfair_lock_unlock(osUnfairLock)
        }
    }
}

class DoublyLinkedList<K, V>{
    var key: K
    var value: V
    var previous: DoublyLinkedList?
    var next: DoublyLinkedList?
    
    init(_ key: K, _ value: V) {
        self.key = key
        self.value = value
    }
}

final class LRUCache<K: Hashable, V> {
    private var maxCapacity: Int
    private var head: DoublyLinkedList<K, V>
    private var tail: DoublyLinkedList<K, V>
    private var cache: [K: DoublyLinkedList<K, V>]
    
    private let lock = UnfairLock()

    init(key: K, value: V, maxCapacity: Int) {
        self.maxCapacity = maxCapacity
        self.cache = [K: DoublyLinkedList<K, V>]()
        self.head = DoublyLinkedList<K, V>(key, value)
        self.tail = DoublyLinkedList<K, V>(key, value)
        self.head.next = self.tail
        self.tail.previous = self.head
        
        NotificationCenter.default.addObserver(self, selector: #selector(receiveMemoryWarning), name: UIApplication.didReceiveMemoryWarningNotification, object: nil)
    }
    
    deinit {
        removeAll()
        NotificationCenter.default.removeObserver(self)
    }
    
    @objc private func receiveMemoryWarning() {
        removeAll()
    }
    
    private func add(_ node: DoublyLinkedList<K, V>){
        let next = head.next
        head.next = node
        node.previous = head
        node.next = next
        next?.previous = node
    }
    
    func removeAll() {
        lock.lock()
        defer { lock.unlock() }

        for (key, node) in cache {
            remove(node)
            cache.removeValue(forKey: key)
        }
        self.head.next = nil
        self.tail.previous = nil
    }
    
    func remove(_ key: K) {
        lock.lock()
        defer { lock.unlock() }

        if let node = cache[key] {
            remove(node)
            cache.removeValue(forKey: key)
        }
    }
    
    private func remove(_ node: DoublyLinkedList<K, V>){
        let previous = node.previous
        let next = node.next
        previous?.next = next
        next?.previous = previous
    }
    
    func get(_ key: K) -> V?{
        lock.lock()
        defer { lock.unlock() }

        if let node = cache[key]{
            remove(node)
            add(node)
            return node.value
        }
        return nil
    }
    
    func put(key: K, value: V){
        lock.lock()
        defer { lock.unlock() }

        if let node = cache[key]{
            remove(node)
            cache.removeValue(forKey: key)
        }else if cache.keys.count >= maxCapacity{
            if let leastNode = tail.previous{
                remove(leastNode)
                cache.removeValue(forKey: leastNode.key)
            }
        }
        let newNode = DoublyLinkedList(key, value)
        cache[key] = newNode
        add(newNode)
    }
    
    subscript(index: K) -> V? {
        get {
            return get(index)
        }
        
        set {
            guard let newValue = newValue else {
                return
            }
            put(key: index, value: newValue)
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末糟描,一起剝皮案震驚了整個濱河市恒水,隨后出現(xiàn)的幾起案子撮慨,更是在濱河造成了極大的恐慌乎串,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,126評論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異乖酬,居然都是意外死亡,警方通過查閱死者的電腦和手機融求,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評論 3 400
  • 文/潘曉璐 我一進(jìn)店門咬像,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人生宛,你說我怎么就攤上這事县昂。” “怎么了陷舅?”我有些...
    開封第一講書人閱讀 169,941評論 0 366
  • 文/不壞的土叔 我叫張陵倒彰,是天一觀的道長。 經(jīng)常有香客問我莱睁,道長待讳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,294評論 1 300
  • 正文 為了忘掉前任仰剿,我火速辦了婚禮创淡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酥馍。我一直安慰自己辩昆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,295評論 6 398
  • 文/花漫 我一把揭開白布旨袒。 她就那樣靜靜地躺著,像睡著了一般术辐。 火紅的嫁衣襯著肌膚如雪砚尽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,874評論 1 314
  • 那天辉词,我揣著相機與錄音必孤,去河邊找鬼。 笑死瑞躺,一個胖子當(dāng)著我的面吹牛敷搪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播幢哨,決...
    沈念sama閱讀 41,285評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼赡勘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了捞镰?” 一聲冷哼從身側(cè)響起闸与,我...
    開封第一講書人閱讀 40,249評論 0 277
  • 序言:老撾萬榮一對情侶失蹤毙替,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后践樱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厂画,經(jīng)...
    沈念sama閱讀 46,760評論 1 321
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,840評論 3 343
  • 正文 我和宋清朗相戀三年拷邢,在試婚紗的時候發(fā)現(xiàn)自己被綠了袱院。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,973評論 1 354
  • 序言:一個原本活蹦亂跳的男人離奇死亡瞭稼,死狀恐怖忽洛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弛姜,我是刑警寧澤脐瑰,帶...
    沈念sama閱讀 36,631評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站廷臼,受9級特大地震影響苍在,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荠商,卻給世界環(huán)境...
    茶點故事閱讀 42,315評論 3 336
  • 文/蒙蒙 一寂恬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧莱没,春花似錦初肉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嘹裂,卻和暖如春妄壶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寄狼。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評論 1 275
  • 我被黑心中介騙來泰國打工丁寄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泊愧。 一個月前我還...
    沈念sama閱讀 49,431評論 3 379
  • 正文 我出身青樓伊磺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親删咱。 傳聞我的和親對象是個殘疾皇子屑埋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,982評論 2 361

推薦閱讀更多精彩內(nèi)容