Quand je lis le code source à partir de java.io.BufferedInputStream.getInIfOpen()
, je ne comprends pas pourquoi il a écrit un code comme celui-ci:
/**
* Check to make sure that underlying input stream has not been
* nulled out due to close; if not return it;
*/
private InputStream getInIfOpen() throws IOException {
InputStream input = in;
if (input == null)
throw new IOException("Stream closed");
return input;
}
Pourquoi utilise-t-il l'alias au lieu d'utiliser la variable de champ in
directement comme ci-dessous:
/**
* Check to make sure that underlying input stream has not been
* nulled out due to close; if not return it;
*/
private InputStream getInIfOpen() throws IOException {
if (in == null)
throw new IOException("Stream closed");
return in;
}
Quelqu'un peut-il donner une explication raisonnable?
java
bufferedinputstream
Saint
la source
la source
Eclipse
, vous ne pouvez pas suspendre un débogueur sur uneif
instruction. Peut- être une raison pour cette variable alias. Je voulais juste jeter ça là-bas. Je spécule, bien sûr.if
déclaration?Réponses:
Si vous regardez ce code hors de son contexte, il n'y a pas de bonne explication pour cet "alias". Il s'agit simplement d'un code redondant ou d'un style de code médiocre.
Mais le contexte est qu'il
BufferedInputStream
s'agit d'une classe qui peut être sous-classée et qu'elle doit fonctionner dans un contexte multi-thread.L'indice est qu'il
in
est déclaré dansFilterInputStream
isprotected volatile
. Cela signifie qu'il ya une chance qu'une sous - classe pourrait atteindre et assignnull
àin
. Compte tenu de cette possibilité, «l'alias» est en fait là pour empêcher une condition de concurrence.Considérez le code sans "alias"
getInIfOpen()
in == null
et voit que cein
n'est pas le casnull
.null
àin
.return in
. Ce qui revientnull
cara
c'est unvolatile
.L '"alias" empêche cela. Maintenant, il
in
est lu une seule fois par le thread A. Si le thread B est affecténull
après le thread A,in
cela n'a pas d'importance. Le thread A lèvera une exception ou renverra une valeur non nulle (garantie).la source
protected
variables sont mauvaises dans un contexte multi-thread.protected
variables dans notre code s'il est multi-thread?Cela est dû au fait que la classe
BufferedInputStream
est conçue pour une utilisation multi-thread.Ici, vous voyez la déclaration de
in
, qui est placée dans la classe parentFilterInputStream
:Comme c'est le cas
protected
, sa valeur peut être modifiée par n'importe quelle sous-classe deFilterInputStream
, y comprisBufferedInputStream
et ses sous-classes. En outre, il est déclarévolatile
, ce qui signifie que si un thread change la valeur de la variable, ce changement sera immédiatement reflété dans tous les autres threads. Cette combinaison est mauvaise, car cela signifie que la classeBufferedInputStream
n'a aucun moyen de contrôler ou de savoir quandin
est modifiée. Ainsi, la valeur peut même être modifiée entre la vérification de null et l'instruction return inBufferedInputStream::getInIfOpen
, ce qui rend effectivement la vérification de null inutile. En lisant la valeur dein
une seule fois pour la mettre en cache dans la variable localeinput
, la méthodeBufferedInputStream::getInIfOpen
est sûre contre les modifications d'autres threads, car les variables locales sont toujours détenues par un seul thread.Il existe un exemple dans
BufferedInputStream::close
, qui est définiin
sur null:Si
BufferedInputStream::close
est appelé par un autre thread pendant l'BufferedInputStream::getInIfOpen
exécution, cela entraînerait la condition de concurrence décrite ci-dessus.la source
compareAndSet()
,CAS
, etc. dans le code et dans les commentaires. J'ai également recherché leBufferedInputStream
code et trouvé de nombreusessynchronized
méthodes. Donc, il est destiné à une utilisation multi-thread, même si je ne l'ai certainement jamais utilisé de cette façon. Quoi qu'il en soit, je pense que votre réponse est correcte!getInIfOpen()
n'est appelé qu'à partir despublic synchronized
méthodes deBufferedInputStream
.C'est un tel code court, mais, théoriquement, dans un environnement multi-thread,
in
peut changer juste après la comparaison, de sorte que la méthode pourrait renvoyer quelque chose qu'elle n'a pas vérifié (elle pourrait renvoyernull
, faisant ainsi exactement la chose à laquelle elle était censée prévenir).la source
in
peut changer entre le moment où vous appelez la méthode et le retour de la valeur (dans un environnement multi-thread)?in
peut changer à tout moment).Je pense que la capture de la variable de classe
in
dans la variable locale permetinput
d'éviter un comportement incohérent en cas dein
modification par un autre thread pendant l'getInIfOpen()
exécution.Notez que le propriétaire de
in
est la classe parente et ne la marque pas commefinal
.Ce modèle est reproduit dans d'autres parties de la classe et semble être un codage défensif raisonnable.
la source