C'est parce que la classe BufferedInputStream
est conçu pour le multi-thread d'utilisation.
Ici, vous voyez la déclaration de in
, qui est placé dans la classe parente FilterInputStream
:
protected volatile InputStream in;
Depuis qu'il est protected
, sa valeur peut être modifiée par aucune sous-classe d' FilterInputStream
, y compris l' BufferedInputStream
et de ses sous-classes. Aussi, il est déclaré volatile
, ce qui signifie que si un thread modifie la valeur de la variable, cette modification est immédiatement prise en compte dans tous les autres threads. Cette combinaison est mauvais, car il s'agit de la classe BufferedInputStream
n'a aucun moyen de contrôle ou de savoir quand in
est changé. Ainsi, la valeur peut encore être changé entre le vérifier la nullité et de l'instruction de retour en BufferedInputStream::getInIfOpen
, ce qui rend effectivement le vérifier la valeur null inutile. Par la lecture de la valeur de in
qu'une seule fois pour mettre en cache dans la variable locale input
, la méthode de BufferedInputStream::getInIfOpen
est protégé contre les modifications d'autres threads, puisque les variables locales sont toujours détenue par un seul thread.
Il y a un exemple dans BufferedInputStream::close
, ce qui définit in
null:
public void close() throws IOException {
byte[] buffer;
while ( (buffer = buf) != null) {
if (bufUpdater.compareAndSet(this, buffer, null)) {
InputStream input = in;
in = null;
if (input != null)
input.close();
return;
}
// Else retry in case a new buf was CASed in fill()
}
}
Si BufferedInputStream::close
est appelé par un autre thread, tout BufferedInputStream::getInIfOpen
est exécutée, cela aurait pour résultat la race des conditions décrites ci-dessus.