2010-02-12 6 views
9

Je suis arrivé précédemment à la conclusion que si vous avez besoin d'une référence SoftReference avec une égalité basée sur la valeur (égal à), la conception est mauvaise, à l'exception d'un interner. Ceci fait suite à Google Collections et à Guava n'incluant pas une telle classe. Mais j'ai rencontré un problème qui, je pense, pourrait utiliser un tel objet.Utilisation potentielle pour SoftReference avec égalité de valeur (égal à)

Nous avons un système de gestion d'actifs dans une ferme de rendu d'effets visuels avec des centaines de processus exécutant le même travail qui ne diffèrent que par le nombre d'images qu'il rend. Nous avons une base de données Oracle qui doit enregistrer tous les actifs utilisés. Au lieu de battre Oracle avec des insertions identiques où un seul réussira de tous les travaux, dans le système de gestion des actifs de niveau intermédiaire, nous pouvons utiliser un HashSet pour enregistrer si l'objet qui serait inséré dans Oracle.

Je pourrais utiliser un Google MapMaker avec une expiration, mais je ne veux pas avoir à vous soucier de l'expiration correcte, nous avons des rendus qui s'exécutent en quelques heures et quelques jours. L'utilisation d'un SoftReference avec une égalité égale équivaut à un bien meilleur moyen pour que la JVM gère automatiquement la récupération de place. Pour d'autres problèmes que je veux résoudre avec un ConcurrentHashMap avec garbage collection, j'utiliserais une référence forte dans HashMap comme clé pour obtenir l'égalité equals() et une SoftReference comme valeur pour que la JVM puisse récupérer quelque chose , mais dans ce cas, la valeur n'a pas d'importance et je n'ai pas de valeur à insérer dans un SoftReference à mettre là. Donc, il semble que l'utilisation d'un SoftReference avec equals() ferait l'affaire.

D'autres suggestions?

+1

Aimez votre question, je me demandais à ce sujet aussi récemment – nanda

+0

Est-ce que 'ResourceBundle' ne fait pas quelque chose comme ça? –

+0

@nanda Ce qui est ajouté à Oracle est une liste d'actifs (disons les noms de fichiers sur un serveur NFS) générés dynamiquement; ResourceBundle ne semble pas être la bonne solution. J'ai juste besoin d'un HashSet pour enregistrer que le nom de fichier a été enregistré dans Oracle, donc 99 autres tentatives pour l'insérer ne gâchent pas les cycles CPU dans Oracle. –

Répondre

1

Dans la plupart des cas, lorsque vous voulez utiliser des références douces avec Google Collections, vous devez appeler

MapMaker.softValues() 

Avec les touches fortes, mais des valeurs douces, les recherches vont utiliser des paires d'égalité et clé-valeur seront les déchets collectés lorsque la mémoire est serré.

+0

Mais je n'ai pas de valeur à associer à la clé, donc la clé est la seule chose qui peut être mise dans une référence douce. –

0

Je pense que cette classe répondra à vos besoins:

import java.util.*; 
import java.lang.ref.*; 

public class SoftSet<T> extends AbstractSet<T> { 

    private final WeakHashMap<T,SoftReference<T>> data = new WeakHashMap<T,SoftReference<T>>(); 

    public boolean add(T t) { 
    return null == data.put(t, new SoftReference<T>(t)); 
    } 

    public boolean remove(Object o) { 
    return null != data.remove(o); 
    } 

    public boolean contains(Object o) { 
    return data.containsKey(o); 
    } 

    public Iterator<T> iterator() { 
    return data.keySet().iterator(); 
    } 

    public int size() { 
    return data.size(); 
    } 

    public void clear() { 
    data.clear(); 
    } 

    public boolean removeAll(Collection<?> c) { 
    return data.keySet().removeAll(c); 
    } 

    public boolean retainAll(Collection<?> c) { 
    return data.keySet().retainAll(c); 
    } 
} 

La façon dont cela devrait fonctionner est qu'une fois la référence souple qui est la valeur est effacée, la valeur est faiblement accessible uniquement et la clé peut être retiré de la carte intérieure.

+0

Peut-être le downvote parce qu'il enveloppe l'objet dans deux références distinctes que nécessaire. Avoir une seule sous-classe SoftReference avec equal() égalité dans un Google ConcurrentHashMap peut être plus propre de cette façon. –

1

Comme il n'y a pas ConcurrentHashSet en utilisant des références douces, il n'y a que deux approches:

1.) Votre approche avec le ConcurrentHashMap

  • Remplacer equals et hashCode dans le SoftReference
  • intérieur de equals et hashCode seulement accéder à l'objet en utilisant SoftReference#get
  • Mettre SoftReference en tant que clé, et tout objet en tant que valeur (seule la valeur null n'est pas autorisée)
  • Si la référence devient obsolète lors de l'accès à hashCode ou est égale, ajoutez la référence à une file d'attente de suppression pour supprimer fréquemment les clés qui sont mortes.
  • Vérifier contient via containsKey

2.) Utilisez un ConcurrentMultimap<Integer, Set<SoftReference<RepLookupEntry>> et utilisez hashCode comme clé, et un ensemble synchronisé de SoftReferences comme valeurs. Lorsque vous obtenez un hit hashCode, vérifiez le contenu de tous les SoftReferences pour l'égalité. Pas très joli, je suis d'accord et difficile à synchroniser.

Si j'étais dans votre position, je n'utiliserais pas du tout les SoftReferences, mais plutôt une ConcurrentHashMap pour conserver de solides références à vos POJO. Chaque fois qu'un nouvel élément arrive, placez-le dans une file d'attente ConcurrentLinkQueue. Si la file d'attente dépasse une certaine limite, commencez par supprimer des éléments de la HashMap.