如何正确使用同步的链接哈希映射 [英] how to use a synchronized linked hash map correctly

查看:194
本文介绍了如何正确使用同步的链接哈希映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



该地图通过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>扩展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);
如果(!arg2)
抛出新的RuntimeException(你没有构建lru映射!);
maxSize = arg0;
}
public LruMap(Map< K,V> arg0){
super(arg0);
抛出新的RuntimeException(你没有构建lru映射!);
}
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实现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(added+(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< piece&& first!= 0){
System.out.println(lru:first!= 0!+ first);
if(throwWhenfirstIsNotZero){throw new RuntimeException(oops);对于(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 my mssed!);
}
}
返回条目;
}
}
public long piece(final long dt){
return dt / period * pieces + dt%period * pieces / period;
}
public boolean throwWhenfirstIsNotZero = true;
保护长片;
public long t0;
protected long stopAtPiece = Long.MAX_VALUE;
public final int period;
public final int piece;
public final Map< Long,Long> lruMap;
}
public class ServerTestCase {
@Before public void setUp()throws Exception {}
@After public void tearDown()throws异常{}
@Test public void testRun(){
server.stopAtPiece = server.pieces;
server.throwWhenfirstIsNotZero = true;
线程线程=新线程(服务器);
thread.setName(server);
thread.start();
while(thread.isAlive()){
for(long i = 0; i< server.piece; i ++)
synchronized(server.lruMap){
server.lruMap获得(ⅰ);
}
}
}
final int period = 2 * 1000;
final int serverPieces = 100;
服务器服务器=新服务器(serverPieces,period);
}


解决方案

如果您正在访问该集合在一个 synchronized(lruMap)块中,那么你可能不想将它包装在 Collections.synchronizedMap() - 使用一个或另一个。这是因为它们可能正在使用不同的锁 - 实际上它几乎是可以肯定的,因为 synchronizedMap()是不可能使用 synchronized(this)



另外我推荐请在此输入链接描述


trying to make an lru map by subclassing linked hash map.

the map is run through collections.synchronized.

all usages of the map are surrounded by a synchronized block. the unit test also fails if they are all removed. one would think they are not necessary since the map was run through collections.synchronized.

one thread puts sequential numbers (0,1,2,3 ...) into the map. removals are handled by removed eldest entry. no one else removes entries from the map.

the other thread gets the data from the map.

the following unit test fails usually at "oops". this is when a non zero number shows up in the first position (it should be zero until the map gets full). other strange things can happen like null values in the entry set.

any pointers will be appreciated.

thanks

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);
}

解决方案

If you are accessing the collection inside a synchronized(lruMap) block, then you probably don't want to wrap it in Collections.synchronizedMap() - use one or the other. This is because they will probably be using different locks - in fact it's almost certain, because it's extremely unlikely that synchronizedMap() is using synchronized(this) internally.

Also I recommend enter link description here

这篇关于如何正确使用同步的链接哈希映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆