- 浏览: 506968 次
- 性别:
- 来自: 北京
-
文章分类
- 全部博客 (250)
- concurrent (11)
- io (1)
- CI (10)
- linux (57)
- windows (2)
- java (38)
- mac (4)
- eclipse (9)
- db (13)
- python (5)
- groovy (5)
- flex (7)
- hibernate (5)
- odb (8)
- netbeans (1)
- web (31)
- book (14)
- erlang (2)
- communication (2)
- virtualization (5)
- jUnit (0)
- jsf (1)
- perl (1)
- java jax-rs (5)
- Jenkins (2)
- Jenkins Plugin (3)
- android (2)
- git (1)
- big data (0)
- 试读 (1)
最新评论
-
yzzy4793:
讲的很清楚,明白
同步synchronized方法和代码块 -
aa51513:
中文乱码式硬伤
Jersey2.x对REST请求处理流程的分析 -
feiwomoshu1991:
...
同步synchronized方法和代码块 -
marshan:
启动失败的原因是加载的类版本冲突,因此你首先要保证依赖的版本和 ...
richfaces中facelet版本升级到2时的典型错误和解决办法 -
zhaohang6688:
请问我按照你的方式修改还是报错 错误信息还是这个 是为什么啊 ...
richfaces中facelet版本升级到2时的典型错误和解决办法
LinkedHashMap是一个现成的LRU实现。但其缺乏并发机制,并且没有实现满载删除条件(removeEldestEntry),因此本文认为LinkedHashMap是预留扩展的LRU类。
本文将继承该类进一步实现LRU缓存。
首先,并发使用可重入锁。对于封读锁后是否可写,封写锁后是否可读的问题,这是一个封锁策略。一般而言,读后,若写,会产生脏数据。写后,若读则没有问题。
可重入锁之读写锁,封锁顺序测试:
package lock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class LockTest1{ final static ReadWriteLock rwlock = new ReentrantReadWriteLock(); final static Lock readLock = rwlock.readLock(); final static Lock writeLock = rwlock.writeLock(); public static void main(String[] args) throws InterruptedException { System.out.println("test readlock-writelock"); lockR2W(); System.out.println("test writelock-readlock"); lockW2R(); System.out.println("test readlock-readlock"); lockRR(); System.out.println("test writelock-writelock"); lockWW(); } private static void lockWW() { writeLock.lock(); System.out.println("w lock."); try { if (writeLock.tryLock(1, TimeUnit.SECONDS)) System.out.println("w lock."); else System.out.println("when w lock, cannot w lock again."); } catch (InterruptedException e0) { e0.printStackTrace(); } try { writeLock.unlock(); System.out.println("w unlock."); writeLock.unlock(); System.out.println("w unlock."); } catch (Exception e) { //ignore; } } private static void lockRR() { readLock.lock(); System.out.println("r lock."); readLock.lock(); System.out.println("r lock."); readLock.unlock(); System.out.println("r unlock."); readLock.unlock(); System.out.println("r unlock."); } private static void lockW2R() throws InterruptedException { writeLock.lock(); System.out.println("w lock."); if (readLock.tryLock(1, TimeUnit.SECONDS)) System.out.println("r lock."); else System.out.println("when w lock, cannot r lock."); writeLock.unlock(); System.out.println("w unlock."); readLock.unlock(); System.out.println("r unlock."); } private static void lockR2W() { readLock.lock(); System.out.println("r lock."); try { if (writeLock.tryLock(1, TimeUnit.SECONDS)) System.out.println("w lock."); else System.out.println("when r lock, cannot w lock."); } catch (InterruptedException e0) { e0.printStackTrace(); } try { readLock.unlock(); System.out.println("r unlock."); writeLock.unlock(); System.out.println("w unlock."); } catch (Exception e) { //ignore; } } }
测试结果:
test readlock-writelock r lock. when r lock, cannot w lock. r unlock. test writelock-readlock w lock. r lock. w unlock. r unlock. test readlock-readlock r lock. r lock. r unlock. r unlock. test writelock-writelock w lock. w lock. w unlock. w unlock.
LRU的意义在于最近被访问的数据总是可以最快从缓存中读取到。因此,下面要测试最新数据的位置和缓存已满时数据的处理。
package lru; import java.util.Iterator; import java.util.Map.Entry; public class LRUTest{ public static void main(String[] args) { int maxCapacity = 5; OjadbMap<Integer, String> lruMap = new OjadbMap<Integer, String>(maxCapacity); for (int i = 0; i < maxCapacity; i++) { lruMap.put(i, "data[" + i + "]"); } lruMap.get(3); Iterator<Entry<Integer, String>> iter = lruMap.entrySet().iterator(); while (iter.hasNext()) { System.out.println(iter.next().getValue()); } System.out.println(); lruMap.put(9, "data[ 9 ]"); Iterator<Entry<Integer, String>> iter1 = lruMap.entrySet().iterator(); while (iter1.hasNext()) { System.out.println(iter1.next().getValue()); } } }
测试结果:
data[0] data[1] data[2] data[4] data[3] //最近访问的数据在队尾。 data[1] data[2] data[4] data[3] data[ 9 ] //最新访问的数据插入队尾(若队满,最老的数据被移除)。
本文使用的LRU缓存类:
(参考:这个类是我的一个开源数据库项目中,缓存部分的实现类。
你可以通过访问http://code.google.com/p/ojadb 查看整个项目)
/******************************************************************************************* * oJadb is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * oJadb is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this library. * If not, see <http://www.gnu.org/licenses/>. * * Author:EricHan * Time:2008-8-28 ******************************************************************************************/ package lru; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class OjadbMap<K, V> extends LinkedHashMap<K, V>{ private static final long serialVersionUID = -6970580442519842034L; private final int maxCapacity; private static final float DEFAULT_LOAD_FACTOR = 0.75f; //private final Lock lock = new ReentrantLock(); private final ReadWriteLock rwlock = new ReentrantReadWriteLock(); private final Lock readLock = rwlock.readLock(); private final Lock writeLock = rwlock.writeLock(); public OjadbMap(int maxCapacity) { super(maxCapacity, DEFAULT_LOAD_FACTOR, true); this.maxCapacity = maxCapacity; } @Override protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) { return size() > maxCapacity; } @Override public boolean containsKey(Object key) { try { readLock.lock(); return super.containsKey(key); } finally { readLock.unlock(); } } @Override public V get(Object key) { try { readLock.lock(); return super.get(key); } finally { readLock.unlock(); } } @Override public V put(K key, V value) { try { writeLock.lock(); return super.put(key, value); } finally { writeLock.unlock(); } } public int size() { try { readLock.lock(); return super.size(); } finally { readLock.unlock(); } } public void clear() { try { writeLock.lock(); super.clear(); } finally { writeLock.unlock(); } } public Collection<Map.Entry<K, V>> getAll() { try { readLock.lock(); return new ArrayList<Map.Entry<K, V>>(super.entrySet()); } finally { readLock.unlock(); } } }
评论
11 楼
火星来客
2009-12-09
mikeandmore 写道
火星来客 写道
mikeandmore 写道
原来也是搞链表鸟。。。嗯。。。还是自己写靠谱。。。-,-
于是
我觉得lz的实现有点问题。。。
readlock和readlock互溶
于是会同时发生get,这估计也是lz想要的。
但是看看hashedlinklist的代码
第323行,会开始对lru queue进行访问,要把当前的访问放在queue head。这会发生争抢。造成链表出现一些诡异的现象。
于是
我觉得lz的实现有点问题。。。
readlock和readlock互溶
于是会同时发生get,这估计也是lz想要的。
但是看看hashedlinklist的代码
第323行,会开始对lru queue进行访问,要把当前的访问放在queue head。这会发生争抢。造成链表出现一些诡异的现象。
这个也是我用synchronized的原因,get操作会修改链表,用ReentrantLock没问题,但是要用同一把锁做get和put,读写锁用在这里不合适
嗯。对。
而且我觉得这个东西如果用spinlock会好一些。。这么短操作不要陷入内核...
250w/s的操作我想对于一个cache来说应该没有问题了,只是在我的测试中cpu上升到95%,应该是内核互斥命令造成的。不知道用spinlock会不会能降低cpu的消耗
10 楼
mikeandmore
2009-12-09
火星来客 写道
mikeandmore 写道
原来也是搞链表鸟。。。嗯。。。还是自己写靠谱。。。-,-
于是
我觉得lz的实现有点问题。。。
readlock和readlock互溶
于是会同时发生get,这估计也是lz想要的。
但是看看hashedlinklist的代码
第323行,会开始对lru queue进行访问,要把当前的访问放在queue head。这会发生争抢。造成链表出现一些诡异的现象。
于是
我觉得lz的实现有点问题。。。
readlock和readlock互溶
于是会同时发生get,这估计也是lz想要的。
但是看看hashedlinklist的代码
第323行,会开始对lru queue进行访问,要把当前的访问放在queue head。这会发生争抢。造成链表出现一些诡异的现象。
这个也是我用synchronized的原因,get操作会修改链表,用ReentrantLock没问题,但是要用同一把锁做get和put,读写锁用在这里不合适
嗯。对。
而且我觉得这个东西如果用spinlock会好一些。。这么短操作不要陷入内核...
9 楼
火星来客
2009-12-09
mikeandmore 写道
原来也是搞链表鸟。。。嗯。。。还是自己写靠谱。。。-,-
于是
我觉得lz的实现有点问题。。。
readlock和readlock互溶
于是会同时发生get,这估计也是lz想要的。
但是看看hashedlinklist的代码
第323行,会开始对lru queue进行访问,要把当前的访问放在queue head。这会发生争抢。造成链表出现一些诡异的现象。
于是
我觉得lz的实现有点问题。。。
readlock和readlock互溶
于是会同时发生get,这估计也是lz想要的。
但是看看hashedlinklist的代码
第323行,会开始对lru queue进行访问,要把当前的访问放在queue head。这会发生争抢。造成链表出现一些诡异的现象。
这个也是我用synchronized的原因,get操作会修改链表,用ReentrantLock没问题,但是要用同一把锁做get和put,读写锁用在这里不合适
8 楼
mikeandmore
2009-12-09
哈哈
原来已经有前辈说过我的问题了。。。
http://www.iteye.com/topic/123856#377584
原来已经有前辈说过我的问题了。。。
http://www.iteye.com/topic/123856#377584
7 楼
mikeandmore
2009-12-09
原来也是搞链表鸟。。。嗯。。。还是自己写靠谱。。。-,-
于是
我觉得lz的实现有点问题。。。
readlock和readlock互溶
于是会同时发生get,这估计也是lz想要的。
但是看看hashedlinklist的代码
第323行,会开始对lru queue进行访问,要把当前的访问放在queue head。这会发生争抢。造成链表出现一些诡异的现象。
于是
我觉得lz的实现有点问题。。。
readlock和readlock互溶
于是会同时发生get,这估计也是lz想要的。
但是看看hashedlinklist的代码
第323行,会开始对lru queue进行访问,要把当前的访问放在queue head。这会发生争抢。造成链表出现一些诡异的现象。
6 楼
mikeandmore
2009-12-09
火星来客 写道
mikeandmore 写道
囧。原来hashlinklist真么神奇
super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
注意第三个参数
于是看代码去鸟。。。。
5 楼
火星来客
2009-12-09
mikeandmore 写道
囧。原来hashlinklist真么神奇
super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
注意第三个参数
4 楼
mikeandmore
2009-12-09
囧。原来hashlinklist真么神奇
他这个lru似乎是直接用hash function搞的?
他这个lru似乎是直接用hash function搞的?
3 楼
火星来客
2009-12-08
我用countdownloadlatch,同步用sync,250w/s,Lock readLock = rwlock.readLock(); 没有试
2 楼
marshan
2009-12-08
我写了个测试,你可以在相同条件下跑跑。然后给出回复。
package lru;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Performance{
static final int loop = 10000;
static final int threadCount = 50;
static OjadbMap<Integer, Integer> lruMap = new OjadbMap<Integer, Integer>(loop);
static ExecutorService exec = Executors.newFixedThreadPool(threadCount);
static long nn = 0;
static int check=0;
public static void main(String[] args) throws InterruptedException {
Performance p = new Performance();
p.start();
}
private void start() throws InterruptedException {
loops();
Thread.sleep(7500);
System.out.println(check+" spend time=" + nn);
System.out.println(" every milli-seconds=" + (check / nn));
lruMap=null;
exec.shutdown();
}
private void loops() {
for (int i = 0; i < threadCount; i++) {
exec.execute(new Thread("thread-" + i){
@Override
public void run() {
final long begin = System.currentTimeMillis();
Random r = new Random();
for (int j = 0; j < loop; j++) {
check++;
int n = r.nextInt(100);
if (null == lruMap.get(n)) {
lruMap.put(n, j);
} else {
}
}
final long end = System.currentTimeMillis();
final long elapsed = end - begin;
nn = nn + elapsed;
}
});
}
}
}[/color][/color]
package lru;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Performance{
static final int loop = 10000;
static final int threadCount = 50;
static OjadbMap<Integer, Integer> lruMap = new OjadbMap<Integer, Integer>(loop);
static ExecutorService exec = Executors.newFixedThreadPool(threadCount);
static long nn = 0;
static int check=0;
public static void main(String[] args) throws InterruptedException {
Performance p = new Performance();
p.start();
}
private void start() throws InterruptedException {
loops();
Thread.sleep(7500);
System.out.println(check+" spend time=" + nn);
System.out.println(" every milli-seconds=" + (check / nn));
lruMap=null;
exec.shutdown();
}
private void loops() {
for (int i = 0; i < threadCount; i++) {
exec.execute(new Thread("thread-" + i){
@Override
public void run() {
final long begin = System.currentTimeMillis();
Random r = new Random();
for (int j = 0; j < loop; j++) {
check++;
int n = r.nextInt(100);
if (null == lruMap.get(n)) {
lruMap.put(n, j);
} else {
}
}
final long end = System.currentTimeMillis();
final long elapsed = end - begin;
nn = nn + elapsed;
}
});
}
}
}[/color][/color]
1 楼
火星来客
2009-12-08
麻烦楼主测一下,50条线程,每条10000次get,set操作时需要的耗时,我也写了一个支持并发的LRUMap,每秒可以支持30w次操作,机器是3G的CPU和2G的内存
发表评论
-
[童虎退壳系列]死锁演示
2011-10-13 01:53 965package creative.fire.multit ... -
[童虎退壳系列]方法加锁测试
2011-10-13 01:34 1183package creative.fire.multit ... -
线程池 浅析
2010-12-03 15:26 1070本文是对java线程池的粗浅分析,视野局限于线程池的基本实现, ... -
并发集合 CopyOnWrite
2010-11-28 01:59 1147CopyOnWriteArrayList 内部结构比较简 ... -
并发集合 Queue
2010-11-28 01:54 1293ArrayBlockingQueue 内部结构 ... -
并发集合 ConcurrentHash
2010-11-21 21:09 1278Synchronized Collections -- ... -
同步器
2010-11-17 02:08 1070Latch 门闩 CountDownLatch 的一个有用特 ... -
线程池的实现
2009-12-19 21:51 1429自己实现了一个简单的线程池。希望回复者讨论技术问题,不要说都已 ... -
LRU缓存的实现之性能测试
2009-12-08 15:19 1435针对上一篇文章,这里给出性能测试:10000条随机数据,50个 ... -
同步synchronized方法和代码块
2009-03-15 22:40 7754同步synchronized方法和代码块 打个比方:一个ob ...
相关推荐
LRU(Least Recently Used)缓存淘汰算法是一种常见的内存管理策略,用于在固定容量的缓存中决定何时替换数据。当缓存满时,最近最少使用的数据将被...通过理解和掌握这些内容,你可以自行编写一个高效的LRU缓存实现。
文档支持目录章节跳转同时还支持阅读器左侧大纲显示和章节快速定位,文档内容完整、条理清晰。文档内所有文字、图表、函数、目录等元素均显示正常,无任何异常情况,敬请您放心查阅与使用。文档仅供学习参考,请勿...
描述:这个项目有点像实验,涉及 3 种不同的 LRU 缓存实现。 一个使用最小堆(通常用于优先级队列)而不是 OrderedDict,第二个使用集合包中的内置 OrderedDict,最后一个使用我自己的 OrderedDict 的简单实现。 ...
PHP LRU缓存实现介绍WTF 是 LRU 缓存吗? LRU 代表最近最少使用。 它是一种缓存类型,通常具有固定容量并丢弃最旧的条目。 如果您需要控制缓存内存使用,这将特别有用。 如果您想了解有关 LRU Cache 的更多详细信息...
在Python版本的LRU缓存实现中,类`LRUCache`包括以下关键部分: 1. 初始化方法`__init__`: 接收一个参数`capacity`,表示缓存的最大容量。创建一个字典`cache`用于存储键值对,一个列表`keys`用于存储键的顺序,...
下面是一个基于`OrderedDict`的LRU缓存实现: ```python from collections import OrderedDict class LRUCache: def __init__(self, capacity: int): self.cache = OrderedDict() self.capacity = capacity ...
单元测试是验证LRU缓存实现正确性的关键步骤。通过编写各种场景的测试用例,如插入、删除、更新和获取数据等,确保在各种情况下缓存都能正确工作。这通常包括边界条件测试,如空缓存、满缓存、已存在的键和不存在的...
以下是简单的LRU缓存实现: ```java import java.util.HashMap; import java.util.LinkedList; import java.util.Map; public class LRUCache, V> implements LRUCache, V> { private int capacity; private Map...
在Go语言中,有许多库可以帮助开发者实现LRU缓存,其中"Go-一个简单高效用于go的LRU缓存包"就是一个这样的工具。这个包为Go程序员提供了简单、高效的LRU缓存接口,便于在应用程序中管理和优化数据存储。 在Go语言中...
在Java中实现LRU缓存机制,不仅可以帮助我们更好地理解和应用数据结构,还能在实际开发中提高程序的性能。本文将详细介绍如何在Java中实现LRU缓存机制,包括其原理、实现方式以及编码实践。 LRU缓存机制是一种非常...
### 链表在LRU缓存淘汰算法中的应用...通过上述方法,双向链表成为了实现LRU缓存淘汰算法的理想选择。它不仅提供了高效的插入和删除操作,还能确保数据项的访问顺序符合最近最少使用的策略,从而提高了缓存的整体性能。
以下是一个简单的LRU缓存实现的Java代码框架: ```java class LRUCache, V> { private int capacity; private HashMap, Node> map; private DoublyLinkedList<Node> list; public LRUCache(int capacity) { ...
“Python—LRU缓存.zip”是一个压缩文件,其中包含了使用Python实现的最近最少使用(Least Recently Used, LRU)缓存算法的代码和相关文档。LRU缓存算法是一种常用的缓存淘汰策略,它根据数据项最近被使用的时间来...
例如,以下是一个简单的LRU缓存实现,使用`LinkedHashMap`的继承方式: ```java public class LRUCache2, V> extends LinkedHashMap, V> { private final int MAX_CACHE_SIZE; public LRUCache2(int cacheSize) ...
`hyperlru`是一个高效的LRU缓存实现,它的简洁代码和优秀性能使得它在JavaScript项目中成为一种理想的缓存解决方案。理解和使用`hyperlru`不仅可以提升开发效率,也有助于深入理解LRU缓存机制和数据结构设计。
Golang LRU缓存golang-lru此lru包提供了实现固定大小线程安全 LRU 缓存的包。它基于 Groupcache 中的缓存。文档完整文档可在Go Packages上找到LRU 缓存示例package mainimport ( "fmt" "github....
在C++中实现LRU缓存淘汰算法通常需要结合哈希表和双链表这两种数据结构。哈希表用于存储键到数据的映射,保证了缓存中数据的快速查找。双链表则用于存储数据的使用顺序,其头部存储最近使用的数据,尾部存储最近最少...
这里的LRUCache类维护了一个双向链表和一个哈希表,用于实现LRU算法。具体实现细节如下: - get方法:首先在哈希表中查找对应的键值对,如果不存在,则返回-1;如果存在,则将对应的节点从双向链表中删除,并将其...
本文将深入探讨如何使用ASyncTask进行异步加载,以及结合LRU缓存策略来优化性能。 首先,我们要理解异步处理的一般方法。在Android中,主线程负责UI更新和用户交互,而耗时操作(如网络请求或数据库操作)应在后台...