2010-10-08 10 views
1

Tous,sécurité Enfiler java

J'ai commencé l'apprentissage des threads Java au cours des derniers jours et avoir lu que sur les scénarios où même après l'utilisation de méthodes de synchroniseur/blocs, le code/classe reste vulnérable aux problèmes de concurrence. Quelqu'un peut-il fournir un scénario où les blocs/méthodes synchronisés échouent? Et, quelle devrait être l'alternative dans ces cas pour assurer la sécurité du fil.

+0

une utilisation correcte du bloc synchronisé ne conduirait pas à des vulnérabilités. –

+1

Je suppose que vous confondez du code qui n'est pas du tout thread-safe (pas de synchronisation) avec du code qui, bien que thread-safe, est vulnérable aux verrous morts. Les verrous morts peuvent uniquement se produire après l'utilisation de blocs/méthodes synchronisés, car ils représentent une situation où des threads séparés attendent l'un l'autre pour libérer des verrous séparés, et ils sont dans un état où ils attendent indéfiniment. –

+0

Voir aussi: http://stackoverflow.com/questions/2458217/why-does-this-code-sometimes-throw-a-nullpointerexception –

Répondre

0

"vulnérable aux problèmes de concurrence" est très vague. Cela aiderait à savoir ce que vous avez réellement lu et où. Deux choses qui viennent à l'esprit:

  • Juste gifles sur « synchronisé » quelque part ne signifie pas que le code est correctement synchronisé - il peut être très difficile de bien faire, et les développeurs manquer souvent des scénarios problématiques, même quand ils pensent qu'ils Fais-le bien.
  • Même si la synchronisation empêche correctement les modifications non déterministes des données, vous pouvez toujours exécuter deadlocks.
1

Scénario 1 impasse classique:

Object Mutex1; 
Object Mutex2; 


public void method1(){ 
    synchronized(Mutex1){ 
     synchronized(Mutex2){ 
     } 
    } 
} 

public void method2(){ 
    synchronized(Mutex2){ 
     synchronized(Mutex1){ 
     } 
    } 
} 

D'autres scénarios comprennent quoi que ce soit avec une ressource partagée même une variable, car un thread pourrait changer le contenu des variables, ou même faire pointer nulle sans l'autre thread savoir. Ecrire à IO a des problèmes similaires, essayez d'écrire du code dans un fichier en utilisant deux threads ou en dehors d'un sockeet.

3

Un comportement correct sous un accès concurrent est un sujet complexe, et ce n'est pas aussi simple que de simplement cliquer sur synchronized sur tout, car vous devez maintenant réfléchir à la manière dont les opérations peuvent s'entrelacer. Par exemple, imaginez que vous ayez une classe comme une liste et que vous souhaitiez la rendre sûre pour les threads. Donc vous faites synchroniser toutes les méthodes et continuez. Il y a des chances, les clients pourraient utiliser votre liste de la manière suivante:

int index = ...; // this gets set somewhere, maybe passed in as an argument 

// Check that the list has enough elements for this call to make sense 
if (list.size() > index) 
{ 
    return list.get(index); 
} 
else 
{ 
    return DEFAULT_VALUE; 
} 

Dans un environnement mono-thread, ce code est parfaitement sûr. Toutefois, si la liste est en cours d'accès (et éventuellement modifié) simultanément, il est possible que la taille de la liste change après l'appel à size(), mais avant l'appel à get(). Ainsi, la liste pourrait "impossiblement" lancer une exception IndexOutOfBoundsException (ou similaire) dans ce cas, même si la taille a été vérifiée auparavant.

Il n'y a pas de raccourci pour résoudre ce problème - vous devez simplement réfléchir soigneusement aux cas d'utilisation de votre classe/interface et vous assurer que vous pouvez réellement les garantir lorsqu'ils sont entrelacés avec d'autres opérations valides. Souvent, cela peut nécessiter une complexité supplémentaire, ou simplement plus de détails dans la documentation. Si la classe de liste hypothétique précise qu'il toujours synchronisé sur son propre moniteur, que spécifique situation pourrait être fixé comme

synchronized(list) 
{ 
    if (list.size() > index) 
    { 
     return list.get(index); 
    } 
} 

mais sous d'autres systèmes de synchronisation, cela ne fonctionnerait pas. Ou il pourrait être trop d'un goulot d'étranglement. Ou forcer les clients à faire les appels multiples dans la même portée lexicale peut être une contrainte inacceptable. Tout dépend de ce que vous essayez de réaliser, de la façon dont vous pouvez rendre votre interface sûre, performante et élégante.

0

Les méthodes synchronisées empêchent l'exécution d'autres méthodes/blocs nécessitant l'exécution du même moniteur lorsque vous les exécutez. Mais si vous avez 2 méthodes, disons int get() et set (int val) et avons une autre méthode qui fait obj.set (1 + obj.get());

et cette méthode s'exécute en deux threads, vous pouvez terminer avec une valeur augmentée de un ou deux, en fonction de facteurs imprévisibles.

Par conséquent, vous devez également protéger en utilisant de telles méthodes aussi (mais seulement si c'est nécessaire).

btw. utiliser chaque moniteur pour le moins de fonctions/blocs possible, de sorte que seuls ceux qui peuvent s'influencer à tort sont synchronisés.

Et essayez d'exposer le moins possible de méthodes nécessitant une protection supplémentaire.

1

Très bons articles sur Java et concurrency modèle en question se trouvent à Angelika Langers website

+0

À condition de lire l'allemand. –

+0

^La puissance de la traduction de Google! :) –

+0

Superbe lien btw .. Merci –