2009-11-27 7 views
2

I ont un code similaire à ce qui suit:synchronisation sur deux ou plusieurs objets (Java)

public class Cache{ 
private final Object lock = new Object(); 
private HashMap<Integer, TreeMap<Long, Integer>> cache = 
    new HashMap<Integer, TreeMap<Long, Integer>>(); 
private AtomicLong FREESPACE = new AtomicLong(102400); 

private void putInCache(TreeMap<Long, Integer> tempMap, int fileNr){ 
    int length; //holds the length of data in tempMap 
    synchronized(lock){ 
    if(checkFreeSpace(length)){ 
    cache.get(fileNr).putAll(tmpMap); 
    FREESPACE.getAndAdd(-length); 
    } 
    } 
} 

private boolean checkFreeSpace(int length){  
    while(FREESPACE.get() < length && thereIsSomethingToDelete()){ 
    // deleteSomething returns the length of deleted data or 0 if 
    // it could not delete anything 
    FREESPACE.getAndAdd(deleteSomething(length)); 
    } 
    if(FREESPACE.get() < length) return true; 
    return false; 
} 
} 

putInCache est appelé par environ 139 fils par seconde. Puis-je être sûr que ces deux méthodes vont se synchroniser sur les deux cache et FREESPACE? En outre, checkFreeSpace() multithread-safe est-ce que je peux être sûr qu'il y aura seulement une invocation de cette méthode à la fois? Le "multithread-safety" de ce code peut-il être amélioré?

+0

(Il ne sert à rien d'utiliser 'AtomicLong' dans ce code.) –

Répondre

2

Vous ne synchronisez généralement pas sur les champs dont vous voulez contrôler l'accès directement. Les champs auxquels vous voulez synchroniser l'accès doivent uniquement être accessibles à partir de blocs synchronisés (sur le même objet) pour être considérés comme sécurisés. Vous le faites déjà en putInCache(). Par conséquent, étant donné que checkFreeSpace() accède à l'état partagé de manière non synchronisée, il n'est pas thread-safe.

+0

et si je déclare' putInCache() 'comme' synchronized'? Cela rendra-t-il les deux méthodes plus «sûres»? – Azimuth

+0

@Azimuth Vous devez protéger l'accès au niveau du champ, ce qui signifie que toutes les méthodes qui accèdent à ces champs doivent se synchroniser sur le même objet de verrouillage. En bref, vous devrez ajouter un bloc synchronisé à checkFreeSpace() aussi. –

3

Pour obtenir une réponse complète à votre question, vous devez afficher les implémentations des méthodes thereIsSomethingToDelete() et deleteSomething(). Etant donné que checkFreeSpace est une méthode publique (est-ce vraiment nécessaire?) Et n'est pas synchronisé, il est possible qu'il puisse être appelé par un autre thread pendant que le bloc synchronisé dans la méthode putInCache() est en cours d'exécution. Cela en soi pourrait ne rien casser, car il semble que la méthode checkFreeSpace peut seulement augmenter la quantité d'espace libre, pas la réduire. Ce qui serait plus grave (et l'exemple de code ne nous permet pas de le déterminer) est que les méthodes thereIsSomethingToDelete() et deleteSomething() ne synchronisent pas correctement leur accès à l'objet cache, en utilisant le même objet. lock utilisé par putInCache().

+0

Merci pour votre réponse. Tout d'abord, 'public' n'est pas un gros problème car ces deux méthodes ne sont appelées que par une autre méthode de la même classe. Quant à 'thereIsSomethingToDelete()' et 'deleteSomething()', je n'ai pas cette méthode en fait. Leur logique est incluse dans la méthode 'checkFreeSpace' mais il serait trop compliqué de mettre tout le code ici. Supposons donc que ces méthodes sont correctement synchronisées. – Azimuth

+0

Désolé, j'ai choisi de mauvaises méthodes pour poser des questions sur. S'il vous plaît jeter un oeil sur la version éditée. – Azimuth

+0

Donc, probablement, putInCache() n'est pas vraiment privé alors non plus (sinon comment la classe pourrait-elle être réellement utilisée). Je pense alors que la classe est threadsafe comme décrit, puisque tout accès à l'état mutable ne peut avoir lieu que si un thread détient le verrou établi par le bloc synchronisé putInCache(). – Henry

Questions connexes