Java op tijd gebaseerde kaart/cache met verlopende sleutels

Oorspronkelijke reden(en) zijn niet opgelost


Antwoord 1, autoriteit 100%

Ja. Google Collections, of Guavazoals het nu heet, heeft iets genaamd MapMakerdie precies dat kan.

ConcurrentMap<Key, Graph> graphs = new MapMaker()
   .concurrencyLevel(4)
   .softKeys()
   .weakValues()
   .maximumSize(10000)
   .expiration(10, TimeUnit.MINUTES)
   .makeComputingMap(
       new Function<Key, Graph>() {
         public Graph apply(Key key) {
           return createExpensiveGraph(key);
         }
       });

Bijwerken:

Vanaf guava 10.0 (uitgebracht op 28 september 2011) zijn veel van deze MapMaker-methoden afgeschaft ten gunste van de nieuwe CacheBuilder:

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
    .maximumSize(10000)
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .build(
        new CacheLoader<Key, Graph>() {
          public Graph load(Key key) throws AnyException {
            return createExpensiveGraph(key);
          }
        });

Antwoord 2, autoriteit 11%

Dit is een voorbeeldimplementatie die ik deed voor dezelfde vereiste en gelijktijdigheid werkt goed. Misschien handig voor iemand.

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * 
 * @author Vivekananthan M
 *
 * @param <K>
 * @param <V>
 */
public class WeakConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
    private static final long serialVersionUID = 1L;
    private Map<K, Long> timeMap = new ConcurrentHashMap<K, Long>();
    private long expiryInMillis = 1000;
    private static final SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss:SSS");
    public WeakConcurrentHashMap() {
        initialize();
    }
    public WeakConcurrentHashMap(long expiryInMillis) {
        this.expiryInMillis = expiryInMillis;
        initialize();
    }
    void initialize() {
        new CleanerThread().start();
    }
    @Override
    public V put(K key, V value) {
        Date date = new Date();
        timeMap.put(key, date.getTime());
        System.out.println("Inserting : " + sdf.format(date) + " : " + key + " : " + value);
        V returnVal = super.put(key, value);
        return returnVal;
    }
    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        for (K key : m.keySet()) {
            put(key, m.get(key));
        }
    }
    @Override
    public V putIfAbsent(K key, V value) {
        if (!containsKey(key))
            return put(key, value);
        else
            return get(key);
    }
    class CleanerThread extends Thread {
        @Override
        public void run() {
            System.out.println("Initiating Cleaner Thread..");
            while (true) {
                cleanMap();
                try {
                    Thread.sleep(expiryInMillis / 2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        private void cleanMap() {
            long currentTime = new Date().getTime();
            for (K key : timeMap.keySet()) {
                if (currentTime > (timeMap.get(key) + expiryInMillis)) {
                    V value = remove(key);
                    timeMap.remove(key);
                    System.out.println("Removing : " + sdf.format(new Date()) + " : " + key + " : " + value);
                }
            }
        }
    }
}

Git Repo Link(met listenerimplementatie)

https://github.com/vivekjustthink/WeakConcurrentHashMap

Proost!!


Antwoord 3, autoriteit 8%

Apache Commons heeft een decorateur voor Map om inzendingen te laten verlopen: PassiveExpiringMap
Het is eenvoudiger dan caches van Guava.

P.S. wees voorzichtig, het is niet gesynchroniseerd.


Antwoord 4, autoriteit 6%

Je kunt mijn implementatievan een zichzelf verlopende hash-kaart uitproberen. Deze implementatie maakt geen gebruik van threads om verlopen items te verwijderen, maar gebruikt in plaats daarvan DelayQueuedie bij elke bewerking automatisch wordt opgeschoond.


Antwoord 5

Het klinkt alsof ehcache overdreven is voor wat je wilt, maar houd er rekening mee dat er geen externe configuratiebestanden voor nodig zijn.

Het is over het algemeen een goed idee om de configuratie naar een declaratief configuratiebestand te verplaatsen (je hoeft dus niet opnieuw te compileren wanneer een nieuwe installatie een andere vervaltijd vereist), maar het is helemaal niet nodig, je kunt het nog steeds configureren programmatisch. http://www.ehcache.org/documentation/user-guide/configuration


Antwoord 6

Google collections (guave) heeft de MapMakerwaarin u een tijdslimiet (voor het verstrijken) kunt instellen en u naar keuze zachte of zwakke referentie kunt gebruiken met behulp van een fabrieksmethode om instanties naar keuze te maken.


Antwoord 7

u kunt Verlopen kaart proberen
http://www.java2s.com/Code/Java/Collections -Data-Structure/ExpiringMap.htm
een les van The Apache MINA Project


Antwoord 8

Als iemand iets eenvoudigs nodig heeft, volgt hier een eenvoudige set waarvan de sleutel verloopt. Het kan gemakkelijk worden omgezet in een kaart.

public class CacheSet<K> {
    public static final int TIME_OUT = 86400 * 1000;
    LinkedHashMap<K, Hit> linkedHashMap = new LinkedHashMap<K, Hit>() {
        @Override
        protected boolean removeEldestEntry(Map.Entry<K, Hit> eldest) {
            final long time = System.currentTimeMillis();
            if( time - eldest.getValue().time > TIME_OUT) {
                Iterator<Hit> i = values().iterator();
                i.next();
                do {
                    i.remove();
                } while( i.hasNext() && time - i.next().time > TIME_OUT );
            }
            return false;
        }
    };
    public boolean putIfNotExists(K key) {
        Hit value = linkedHashMap.get(key);
        if( value != null ) {
            return false;
        }
        linkedHashMap.put(key, new Hit());
        return true;
    }
    private static class Hit {
        final long time;
        Hit() {
            this.time = System.currentTimeMillis();
        }
    }
}

Antwoord 9

Normaal gesproken moet een cache objecten enige tijd bewaren en enige tijd later blootleggen. Wat een goed moment is om een ​​object vast te houdenhangt af van het gebruik. Ik wilde dat dit ding eenvoudig was, geen threads of planners. Deze aanpak werkt voor mij. In tegenstelling tot SoftReferences, zijn objecten gegarandeerd een minimale hoeveelheid tijd beschikbaar. Ze blijven echter niet in het geheugen totdat de zon verandert in een rode reus.

Als gebruiksvoorbeeld denk aan een traag reagerend systeem dat in staat zal zijn om te controleren of een verzoek recentelijk is gedaan, en in dat geval de gevraagde actie niet twee keer uit te voeren, zelfs als een hectische gebruiker meerdere keren op de knop drukt. Maar als dezelfde actie enige tijd later wordt aangevraagd, wordt deze opnieuw uitgevoerd.

class Cache<T> {
    long avg, count, created, max, min;
    Map<T, Long> map = new HashMap<T, Long>();
    /**
     * @param min   minimal time [ns] to hold an object
     * @param max   maximal time [ns] to hold an object
     */
    Cache(long min, long max) {
        created = System.nanoTime();
        this.min = min;
        this.max = max;
        avg = (min + max) / 2;
    }
    boolean add(T e) {
        boolean result = map.put(e, Long.valueOf(System.nanoTime())) != null;
        onAccess();
        return result;
    }
    boolean contains(Object o) {
        boolean result = map.containsKey(o);
        onAccess();
        return result;
    }
    private void onAccess() {
        count++;
        long now = System.nanoTime();
        for (Iterator<Entry<T, Long>> it = map.entrySet().iterator(); it.hasNext();) {
            long t = it.next().getValue();
            if (now > t + min && (now > t + max || now + (now - created) / count > t + avg)) {
                it.remove();
            }
        }
    }
}

Antwoord 10

Guava-cache is eenvoudig te implementeren. We kunnen de sleutel op tijd laten verlopen met behulp van guave-cache. Ik heb de volledige post gelezen en hieronder geeft de sleutel van mijn studie.

cache = CacheBuilder.newBuilder().refreshAfterWrite(2,TimeUnit.SECONDS).
              build(new CacheLoader<String, String>(){
                @Override
                public String load(String arg0) throws Exception {
                    // TODO Auto-generated method stub
                    return addcache(arg0);
                }
              }

Referentie: guave-cachevoorbeeld

Other episodes