LRU简介
LRU(Least Recently Used),即最近最少使用,是一种常用的页面置换算法 ,当需要存入的内容大于临界值的时候,选择最近最少使用的进行淘汰。
如果使用简单的数据结构描述的话,当前有一个栈,但是与栈不同的是,可以随时访问栈中的元素,并且访问过后将当前访问元素置于栈顶。
使用Kotlin写一个LruCache
实现原理
如果写一个缓存的话,一般都是key ,value 类型的,那么自然就会想到HashMap ,但是HashMap 是无序的。所以我们考虑使用LinkedHashMap ,它内部在每一个Node 节点上新增了before和after 做成双向链表,用于记录指向顺序,可以表示插入顺序/访问顺序 。
我们这里就是用到其的访问顺序 。这样每次我们从LinkedHashMap 里面获取值的时候,该值就会跑到链表尾部,插入一个值也是在链表尾部。这样就完美实现类最近最少访问 。接下来只需要在每次向map 存值的时候,将大于我们所设置好的最大size 的从栈头部便利去除即可。
代码
class LruCache<K, V>(maxSize: Int) {
private var currentSize = 0
var maxSize = maxSize
set(value) {
if (value < 0) {
throw IllegalStateException("maxSize 不允许小于0!")
}
synchronized(this) {
field = value
trimToSize()
}
}
get() {
synchronized(this) {
return field
}
}
private val cache = LinkedHashMap<K, V>(1 shl 4, 0.75F, true)
var customSizeOf: ((key: K, value: V) -> Int)? = null
private fun trimToSize() {
synchronized(this) {
if (currentSize < 0 || (cache.isEmpty() && currentSize != 0)) {
throw IllegalStateException("缓存size记录错误")
}
while (currentSize > maxSize) {
val iterator = cache.entries.iterator()
if (iterator.hasNext()) {
val (key, value) = iterator.next()
currentSize -= sizeOf(key, value)
iterator.remove()
}
}
}
}
private fun <T> nullCheck(message: String, any: T?): T {
if (any == null) {
throw NullPointerException(message)
}
return any
}
operator fun get(key: K?): V? {
nullCheck("key 不允许等于 null", key)
return cache[key]
}
operator fun set(key: K?, value: V?): V? {
nullCheck("key 不允许等于 null", key)
nullCheck("value 不允许等于 null", value)
val oldValue = synchronized(this) {
val size = sizeOf(key!!, value!!)
if (size > maxSize) {
return null
}
currentSize += size
cache.put(key, value)?.also { oldValue ->
currentSize -= sizeOf(key, oldValue)
}
}
trimToSize()
return oldValue
}
private fun sizeOf(key: K, value: V): Int {
val snapSizeOf = customSizeOf
if (snapSizeOf != null) {
return snapSizeOf(key, value)
}
return 1
}
fun clearAll() {
maxSize = 0
}
}
代码GIT地址:????????????????????????里面有TestActivity 包含具体使用方法。
创作不易,如有帮助一键三连咯🙆?♀?。欢迎技术探讨噢!
|