[Remarque de chiccodoro: Une explication de pourquoi/quand les fuites this
peut provoquer des problèmes, même si la fuite de la déclaration est placé en dernier dans le constructeur:]
Dernier champ sémantique est différent de "normal" champ sémantique. Un exemple,
Nous jouons un jeu en réseau. Permet de rendre un objet de Jeu de la récupération de données à partir du réseau et un Joueur de l'objet qui est à l'Écoute des événements à partir du jeu à agir en conséquence. Le jeu objet cache tous les détails du réseau, le joueur est seulement intéressé par les événements:
import java.util.*;
import java.util.concurrent.Executors;
public class FinalSemantics {
public interface Listener {
public void someEvent();
}
public static class Player implements Listener {
final String name;
public Player(Game game) {
name = "Player "+System.currentTimeMillis();
game.addListener(this);//Warning leaking 'this'!
}
@Override
public void someEvent() {
System.out.println(name+" sees event!");
}
}
public static class Game {
private List<Listener> listeners;
public Game() {
listeners = new ArrayList<Listener>();
}
public void start() {
Executors.newFixedThreadPool(1).execute(new Runnable(){
@Override
public void run() {
for(;;) {
try {
//Listen to game server over network
Thread.sleep(1000); //<- think blocking read
synchronized (Game.this) {
for (Listener l : listeners) {
l.someEvent();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
public synchronized void addListener(Listener l) {
listeners.add(l);
}
}
public static void main(String[] args) throws InterruptedException {
Game game = new Game();
game.start();
Thread.sleep(1000);
//Someone joins the game
new Player(game);
}
}
//Code runs, won't terminate and will probably never show the flaw.
Semble tout bon: l'accès à la liste est correctement synchronisé. Le problème, c'est que dans cet exemple les fuites le Joueur.ce Jeu, qui est en cours d'exécution d'un thread.
La finale est assez effrayant:
...les compilateurs ont une grande liberté de déplacer le lit de finale champs à travers la synchronisation des obstacles...
Ce joli beaucoup de défaites toutes bonne synchronisation. Mais heureusement
Un thread qui ne peut voir une référence à un objet après que l'objet a été complètement initialisé, il est garanti à voir le initialisé correctement les valeurs pour l'objet en final
champs.
Dans l'exemple, le constructeur écrit les objets de référence à la liste. (Et n'a donc pas été complètement initialisé encore, puisque le constructeur n'a pas fini.) Après l'écriture, le constructeur n'est pas encore fait. Il suffit de le renvoyer au constructeur, mais imaginons qu'il n'a pas encore. Maintenant, l'exécuteur testamentaire pourrait faire son travail et de diffuser des événements pour tous les auditeurs, y compris les pas encore initialisé l'objet de joueur! Le dernier champ du joueur (nom) ne peut pas être écrit, ce qui donnera l'impression null sees event!
.