Question

Se référant à mon question précédente sur des objets construits incomplètement , j'ai deuxième question. Comme Jon Skeet a fait remarquer, il y a une barrière de mémoire implicite à la fin d'un constructeur qui veille à ce que les champs de final sont visibles à toutes les discussions. Mais si un constructeur appelle un autre constructeur; est-il une telle barrière de mémoire à la fin de chacun d'eux, ou seulement à la fin de celui qui nous avait appelé en premier lieu? Autrement dit, lorsque la solution "mauvaise" est:

public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(
            new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            });
    }
}

Et le correct serait une version de méthode usine:

public class SafeListener {
    private final EventListener listener;

    private SafeListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        }
    }

    public static SafeListener newInstance(EventSource source) {
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }
}

Est-ce que trop les travaux suivants, ou non?

public class MyListener {
    private final EventListener listener;

    private MyListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        }
    }

    public MyListener(EventSource source) {
        this();
        source.register(listener);
    }
}

Mise à jour: La question essentielle est que est this() garanti à fait appel le constructeur privé ci-dessus (dans ce cas, il y aurait la barrière où l'intention et tout serait en sécurité ), ou est-il possible que le constructeur privé obtient inline dans l'un public une optimisation pour sauver une barrière de mémoire (dans ce cas, il n'y aurait pas un obstacle jusqu'à la fin du constructeur public )?

sont les règles de this() définies précisément quelque part? Sinon, je pense que nous devons supposer que les constructeurs inline chaînés est permis, et probablement quelques JVMs ou peut-être même javacs le font.

Était-ce utile?

La solution

Je pense qu'il est sûr que le modèle de mémoire java stipule que:

  

Soit o un objet, et c être un constructeur pour o dans lequel une finale   champ f est écrit. Une action de gel sur le champ finale f de o a lieu   lorsque c sorties, normalement ou brusquement. Notez que si l'on   constructeur invoque un autre constructeur, et le constructeur invoqué   définit un champ final, le gel pour le champ final a lieu à la   fin du constructeur invoqué.

Autres conseils

  

Un objet est considéré être initialisé complètement lorsque ses finitions constructeur.

Ceci est également valable pour les constructeurs chaînés.

Si vous devez vous inscrire dans le constructeur définit l'auditeur comme une classe interne statique. C'est sûr.

Votre deuxième version est incorrecte, car il permet à la « cette » référence pour échapper au processus de construction. Avoir « cette » évasion invalident les garanties de sécurité d'initialisation qui donnent champs final leur sécurité.

Pour répondre à la question implicite, la barrière à la fin de la construction arrive seulement à la fin de la construction de l'objet. L'intuition d'un lecteur offert à propos inline est un utile; du point de vue du modèle mémoire de Java, les limites de la méthode n'existent pas.

EDIT Après le commentaire qui a suggéré le compilateur inline les chances constructeur privé (je n'y avais pas pensé que l'optimisation) sont que le code sera dangereux. Et le pire code multithread est dangereux qui est semble fonctionner, vous êtes donc mieux éviter complètement. Si vous voulez jouer des tours différents (vous ne voulez vraiment éviter l'usine pour une raison quelconque) envisager d'ajouter une enveloppe pour garantir la cohérence des données dans l'objet de mise en œuvre interne et enregistrer dans l'objet externe.


Je pense que ce sera fragile mais ok. Le compilateur ne peut pas savoir si le constructeur interne sera appelé uniquement à partir d'autres constructeurs ou non, il doit faire en sorte que le résultat serait correct pour le code d'appel que le constructeur interne, donc quel que soit le mécanisme qu'il utilise (barrière de mémoire?) A être mis en place là-bas.

Je suppose que le compilateur ajouterait la barrière de mémoire à la fin de chaque constructeur. Le problème est toujours là: vous passez la référence this à tout autre code (éventuellement d'autres threads) avant qu'elle ne soit entièrement construit --Que est bad--, mais si la seule'construction' qui reste enregistre l'auditeur, le état de l'objet est aussi stable que ce sera jamais.

La solution est fragile qu'un autre jour, vous ou un autre programmeur peut avoir besoin d'ajouter un autre membre à l'objet et peut oublier que les constructeurs chaînés est un tour de concomitance et peut décider d'initialiser le terrain dans le constructeur public et, ce faisant, ajouter un disque pour détecter la course potentielle de données dans votre application, donc je voudrais essayer d'éviter cette construction.

BTW: La sécurité deviné peut-être tort. Je ne sais pas comment complexe / smart est le compilateur, et si la barrière de mémoire (ou similaire) est quelque chose qu'il pourrait essayer d'optimiser loin ... puisque le constructeur est privé le compilateur n'avoir suffisamment d'informations pour savoir qu'il est seulement appelé d'autres constructeurs, et fournit suffisamment d'informations pour déterminer que le mécanisme de synchronisation n'est pas nécessaire dans le constructeur interne ...

Échapper référence d'objet en c-teur peut publier un objet construit de manière incomplète. Cela est vrai même si la publication est la dernière déclaration du constructeur .

Votre SafeListener pourrait ne pas se comporter ok dans un environnement concurrent, même si c-tor inline est effectuée (que je pense que ce n'est pas - penser à la création d'objets à l'aide de la réflexion en accédant à c-tor privé).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top