同步不起作用

时间:2012-03-15 11:40:04

标签: java map synchronization

我有以下代码,我正在尝试编写LRU缓存。我有一个跑步者类,我正在对缓存的随机容量运行。但是,缓存大小超过容量。当我使FixLRU方法同步时,当缓存大小超过100时它变得更准确但是它变得更慢。当我删除synchronized关键字时,缓存变得不那么准确。

如何使这项工作正常?更准确的?

import java.util.concurrent.ConcurrentHashMap;

public abstract class Cache<TKey, TValue> implements ICache<TKey,TValue>{

    private final ConcurrentHashMap<TKey,TValue> _cache;

    protected Cache()
    {
        _cache=  new ConcurrentHashMap<TKey, TValue>();
    }

    protected Cache(int capacity){
        _cache = new ConcurrentHashMap<TKey, TValue>(capacity);
    }

    @Override
    public void Put(TKey key, TValue value) {
        _cache.put(key, value);
    }

    @Override
    public TValue Get(TKey key) {
        TValue value = _cache.get(key);

        return value;
    }

    @Override
    public void Delete(TKey key) {
        _cache.remove(key);
    }

    @Override
    public void Purge() {
        for(TKey key : _cache.keySet()){
            _cache.remove(key);
        }
    }

    public void IterateCache(){

        for(TKey key: _cache.keySet()){
            System.out.println("key:"+key+" , value:"+_cache.get(key));
        }

    }

    public int Count()
    {
        return _cache.size();
    }


}


import java.util.concurrent.ConcurrentLinkedQueue;

public class LRUCache<TKey,TValue> extends Cache<TKey,TValue> implements ICache<TKey, TValue> {

    private ConcurrentLinkedQueue<TKey> _queue;
    private int capacity;
    public LRUCache(){
        _queue = new ConcurrentLinkedQueue<TKey>();
    }

    public LRUCache(int capacity){
        this();
        this.capacity = capacity;
    }

    public void Put(TKey key, TValue value)
    { 
        FixLRU(key);

        super.Put(key, value);  
    }

    private void FixLRU(TKey key)
    {
        if(_queue.contains(key))
        {
            _queue.remove(key);
            super.Delete(key);
        }

        _queue.offer(key);

        while(_queue.size() > capacity){
            TKey keytoRemove =_queue.poll();
            super.Delete(keytoRemove);
        }
    }

    public TValue Get(TKey key){

        TValue _value = super.Get(key);

        if(_value == null){
            return null;
        }

        FixLRU(key);

        return _value;
    }

    public void Delete(TKey key){

        super.Delete(key);
    }

}

public class RunningLRU extends Thread{

    static LRUCache<String, String> cache = new LRUCache<String, String>(50);

    public static void main(String [ ] args) throws InterruptedException{

        Thread t1 = new RunningLRU();
        t1.start();
        Thread t2 = new RunningLRU();
        t2.start();
        Thread t3 = new RunningLRU();
        t3.start();
        Thread t4 = new RunningLRU();
        t4.start();
        try {
            t1.join();
            t2.join();
            t3.join();
            t4.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println(cache.toString());
        cache.IterateCache();
        System.out.println(cache.Count());

    }

    @Override
    public void run() {
        for(int i=0;i<100000;i++)
            cache.Put("test"+i, "test"+i);
    }

}

2 个答案:

答案 0 :(得分:2)

我会在添加您的条目​​后清理其他条目。这样可以最大限度地缩短缓存大于您想要的时间。您还可以触发size()来执行清理。

  

有关如何使其正常工作的任何想法?

您的测试是否反映了您的应用程序的行为方式?当您没有锤击它时,缓存可能正常(或更接近它)。 ;)

如果此测试确实反映了您的应用程序行为,则可能LRUCache不是最佳选择。

答案 1 :(得分:2)

您的问题似乎是您没有使用put方法putIfAbsent()的特殊 synchronized 版本。如果您不使用它,则ConcurrentHashMap的行为就像同步一样 - 就像普通的地图,例如HashMap。

当您使用它时,您必须继续仅使用返回的值,因此您的Put()方法没有正确的签名(它应该返回{{1} })支持并发。您需要重新设计界面。

此外,在java land中,与.Net land不同,我们使用前导小写命名我们的方法,例如TValue,而不是put()。因此,您可以重命名您的方法。