69 votes

Pourquoi les constructeurs Java ne peuvent-ils pas être synchronisés?

Selon le Langage Java Spécification, les constructeurs ne peuvent pas être marquées synchronisé parce que les autres threads ne peuvent pas voir l'objet en cours de création jusqu'à ce que le fil de la création, il l'a terminé. Cela semble un peu bizarre, parce que je ne peux en effet avoir un autre thread voir l'objet, alors qu'il est en cours de construction:

public class Test {
    public Test() {
       final Test me = this;
       new Thread() {
           @Override
           public void run() {
               // ... Reference 'me,' the object being constructed
           }
       }.start();
    }
}

Je sais que c'est un joli exemple artificiel, mais il semble que dans la théorie que quelqu'un pourrait trouver une façon plus réaliste cas où le marquage le constructeur synchronisé serait légitime afin de prévenir les courses avec son fils comme celui-ci.

Ma question est la suivante: est-il une raison que Java serait d'interdire le modificateur synchronized sur un constructeur? Peut-être que mon exemple ci-dessus est erronée, ou peut-être il n'y a vraiment aucune raison et c'est une conception arbitraire de la décision. Dans les deux cas, je suis très curieux et j'aimerais vraiment connaître la réponse.

Merci beaucoup!

32voto

Paŭlo Ebermann Points 35526

Si vous avez vraiment besoin de synchronisation du reste du constructeur contre tout les threads qui, de toute façon, obtient une référence à votre n'est pas encore totalement construit un objet, vous pouvez utiliser une synchronisation de bloc:

public class Test {
    public Test() {
       final Test me = this;
       synchronized(this) {
          new Thread() {
             @Override
             public void run() {
                // ... Reference 'me,' the object being constructed
                synchronized(me) {
                   // do something dangerous with 'me'.
                }
             }
          }.start();
          // do something dangerous with this
       }
    }
}

Il est généralement considéré mauvais style de "donner" votre pas-encore-objet construit, donc, en parallèle, un constructeur n'est pas nécessaire.


Dans certains cas de coin en parallèle, un constructeur serait utile. Voici un exemple plus réaliste exemple, à partir de la discussion de Bozho de réponse:

public class SuperClass {

   public SuperClass() {
       new Thread("evil") { public void run() {
          doSomethingDangerous();
       }}).start();
       try {
          Thread.sleep(5000);
       }
       catch(InterruptedException ex) { /* ignore */ }
   }

   public abstract void doSomethingDangerous();

}

public class SubClass extends SuperClass {
    int number;
    public SubClass () {
        super();
        number = 2;
    }

    public synchronized void doSomethingDangerous() {
        if(number == 2) {
            System.out.println("everything OK");
        }
        else {
            System.out.println("we have a problem.");
        }
    }

}

Nous voulons que l' doSomethingDangerous() méthode n'est appelée qu'après la construction de notre objet sous-classe est complète, par exemple, nous voulons seulement le "tout est OK" de sortie. Mais dans ce cas, lorsque vous ne pouvez modifier votre sous-classe, vous n'avez aucune chance d'y parvenir. Si le constructeur pourrait être synchronisée, elle permettrait de résoudre le problème.

Donc, ce que nous apprenons à ce sujet: ne jamais faire quelque chose comme je l'ai fait ici dans le constructeur de la superclasse, si votre classe n'est pas définitive et ne pas appeler n'importe quel non-finale méthodes de votre classe à partir de votre constructeur.

18voto

assylias Points 102015

La question a été soulevée sur une liste de discussion utilisé par les rédacteurs de la Java simultanées de l'API et la Java du Modèle de Mémoire. Plusieurs réponses ont été données, en particulier Hans Boehm a répondu:

Certains d'entre nous (moi y compris l'IIRC) fait valoir au cours de la Java du modèle de mémoire de délibérations qui synchronisé les constructeurs devraient être autorisés. Maintenant, je pouvais aller de toute façon. Code Client ne doit pas utiliser des courses pour communiquer la référence, donc il ne devrait pas d'importance. Mais si vous ne faites pas confiance aux clients de [votre], je pense que synchronisés constructeurs pourraient éventuellement être utile. Et c'était bien le raisonnement final de champ sémantique. [...] Comme le dit David, vous pouvez utiliser des blocs synchronisés.

9voto

Bozho Points 273663

Parce que synchronized garantit que les actions sur les mêmes objets ne doivent pas être effectuées par plusieurs threads. Et quand le constructeur s'appelle, vous n'avez toujours pas l'objet. Il est logiquement impossible pour deux threads d'accéder au constructeur du même objet.

Dans votre exemple, même si une méthode est appelée par le nouveau thread, il ne s'agit plus du constructeur, mais de la méthode cible en cours de synchronisation ou non.

5voto

Yishai Points 42417

Dans votre exemple, le constructeur n'est appelé qu'une seule fois à partir d'un thread.

Oui, il est possible d'obtenir une référence à une incomplètement Objet construit (certaines discussions autour d'un double contrôle de verrouillage et pourquoi il est cassé révéler ce problème), cependant, pas en appelant le constructeur une deuxième fois.

Synchronisé sur le constructeur de prévenir les deux fils de l'appel du constructeur, sur le même Objet en même temps, et ce n'est pas possible, comme il n'est jamais possible d'appeler le constructeur sur une instance de l'objet à deux reprises, période.

5voto

Aniket Thakur Points 10135

La section Modificateurs de constructeur de JLS indique clairement

 There is no practical need for a constructor to be synchronized, because it would
lock the object under construction, which is normally not made available to other
threads until all constructors for the object have completed their work.
 

Il n'est donc pas nécessaire que le constructeur soit synchronisé.

De plus, il n'est pas recommandé de donner la référence aux objets (this) avant la création de l'objet. Une des situations ambiguës possibles serait de donner la référence aux objets. Le constructeur de la superclasse lors de la création de l’objet sous-classe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X