试图通过子类化链接的哈希映射来制作 lru 映射。
地图通过 collections.synchronized 运行。
地图的所有用法都被一个同步块包围。如果它们都被删除,单元测试也会失败。有人会认为它们没有必要,因为地图是通过 collections.synchronized 运行的。
一个线程将序列号 (0,1,2,3 ...) 放入地图中。删除由已删除的最旧条目处理。没有其他人从地图中删除条目。
另一个线程从地图中获取数据。
以下单元测试通常在“oops”处失败。这是当一个非零数字出现在第一个位置时(它应该是零,直到地图变满)。其他奇怪的事情可能会发生,例如条目集中的空值。
任何指针将不胜感激。
谢谢
import static org.junit.Assert.*;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
class LruMap<K,V> extends LinkedHashMap<K,V> {
public LruMap() {
super(defaultMaxSize+1,.75f,true);
maxSize=defaultMaxSize;
}
public LruMap(int arg0) {
super(arg0+1,.75f,true);
maxSize=arg0;
}
public LruMap(int arg0,float arg1) {
super(arg0+1,arg1,true);
maxSize=arg0;
}
public LruMap(int arg0,float arg1,boolean arg2) {
super(arg0+1,arg1,arg2);
if(!arg2)
throw new RuntimeException("you did not construct an lru map!");
maxSize=arg0;
}
public LruMap(Map<K,V> arg0) {
super(arg0);
throw new RuntimeException("you did not construct an lru map!");
}
public boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return size()>maxSize;
}
public final int maxSize;
public static final int defaultMaxSize=2048;
static final long serialVersionUID=0;
}
class Server implements Runnable {
public Server(final int pieces,final int period) {
this.pieces=pieces;
this.period=period;
lruMap=Collections.synchronizedMap(new LruMap<Long,Long>(3*pieces/2));
}
@Override public void run() {
t0=System.currentTimeMillis();
while(piece<stopAtPiece) {
final long dt=System.currentTimeMillis()-t0;
final long target=piece(dt);
System.out.println("adding "+(target-piece+1)+" items");
for(;piece<=target;piece++) {
synchronized(lruMap) {
lruMap.put(piece,piece);
}
}
checkMap(piece,true);
try {
Thread.sleep(100);
} catch(InterruptedException e) {
e.printStackTrace();
break;
}
}
}
Map.Entry<Long,Long>[] checkMap(final long n,boolean print) {
synchronized(lruMap) {
Map.Entry<Long,Long>[] entries=null;
if(lruMap.size()>0) {
final Set<Map.Entry<Long,Long>> entrySet=lruMap.entrySet();
entries=new Map.Entry[entrySet.size()];
entrySet.toArray(entries);
long first=entries[0].getKey();
long last=entries[entries.length-1].getKey();
if(print)
for(Map.Entry<Long,Long> entry:entries)
System.out.print(entry.getKey()+" ");
System.out.println();
if(n<pieces&&first!=0) {
System.out.println("lru: first!=0! "+first);
if(throwWhenfirstIsNotZero) { throw new RuntimeException("oops"); }
}
for(int i=0;i<entries.length-1;i++) {
long p0=entries[i].getKey();
long p1=entries[i+1].getKey();
if(p0>p1)
System.out.println("out of order! "+p0+" "+p1);
else if(p0==p1)
System.out.println("dupicate "+p0+" "+p1);
else if(p0+1==p1)
; // ok
else if(p0+1<p1)
System.out.println("skipped "+p0+" "+p1);
else System.out.println("some case i mssed!");
}
}
return entries;
}
}
public long piece(final long dt) {
return dt/period*pieces+dt%period*pieces/period;
}
public boolean throwWhenfirstIsNotZero=true;
protected long piece;
public long t0;
protected long stopAtPiece=Long.MAX_VALUE;
public final int period;
public final int pieces;
public final Map<Long,Long> lruMap;
}
public class ServerTestCase {
@Before public void setUp() throws Exception {}
@After public void tearDown() throws Exception {}
@Test public void testRun() {
server.stopAtPiece=server.pieces;
server.throwWhenfirstIsNotZero=true;
Thread thread=new Thread(server);
thread.setName("server");
thread.start();
while(thread.isAlive()) {
for(long i=0;i<server.piece;i++)
synchronized(server.lruMap) {
server.lruMap.get(i);
}
}
}
final int period=2*1000;
final int serverPieces=100;
Server server=new Server(serverPieces,period);
}