算法 LRU
在Linux内存管理系统中,为了解决内存不够用问题,使用了分页存储。
即将一个程序分为若干个大小为4K(默认)的页,程序运行时需要什么就将其加载到内存中,这样可以使有限的内存运行更多的进程。然而内存还是会出现已满的时候,所以此时加载的页该如何分配?
于是Linux使用了LRU算法:
将最近最少使用的页从内存移动到磁盘中,将新的页加入内存。
关键数据结构:哈希表+双向链表。 可以在O(1)时间复杂度找到需要移动的元素。并且在O(1)时间复杂度将元素移除。
示例代码:
1、定义节点类Node:
public class Node<k,v> { k key; v value; Node<k, v> next; Node<k, v> prev; public Node() { } public Node(k key, v value) { this.key = key; this.value = value; } @Override public String toString() { return "Node{" + "key=" + key + ", value=" + value + '}'; } }
2、定义哈希双向链表:
import java.util.HashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReentrantLock; public class LRUHashList<k,v> { Node<k, v> head = new Node<>(); Node<k, v> tail= new Node<>(); private final int maxcache; private volatile int size; private HashMap<k, Node<k,v>> hashMap = new HashMap<>(); ReentrantLock reentrantLock = new ReentrantLock(); public LRUHashList(int maxcache) { this.maxcache = maxcache; head.next = tail; tail.prev = head; } private void addNode(Node<k,v> node){ node.next = head.next; node.prev = head; head.next.prev = node; head.next = node; } private void delNode(Node<k,v> node){ node.prev.next = node.next; node.next.prev = node.prev; node.prev = null; node.next = null; } public void put(k key, v val){ reentrantLock.lock(); Node<k,v> newnode = hashMap.get(key); if(newnode == null){ Node<k, v> node = new Node<>(key, val); if(size < maxcache){ size++; }else { hashMap.remove(tail.prev.key); delNode(tail.prev); } addNode(node); hashMap.put(key, node); }else{ newnode.value = val; delNode(newnode); addNode(newnode); } reentrantLock.unlock(); } public Node<k,v> get(k key){ reentrantLock.lock(); Node<k, v> node = hashMap.get(key); if(node != null){ delNode(node); addNode(node); } reentrantLock.unlock(); return node; } @Override public String toString() { return "LRUHashList{" + "hashMap=" + hashMap + '}'; } public int getSize(){ return this.size; } public static void main(String[] args) { LRUHashList<Integer,String> list = new LRUHashList<Integer, String>(2); int count = 10; CountDownLatch countDownLatch = new CountDownLatch(count); for (int i = 0; i < count; i++) { new Thread(()->{ int j = (int) (Math.random()*10); list.put(j,"33"); System.out.println(Thread.currentThread().getName() + " " + j); countDownLatch.countDown(); }, "00"+i).start(); // try { // Thread.sleep(1000); // } catch (InterruptedException e) { // e.printStackTrace(); // } } try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(" " + list.getSize() + list); } }
3、输出