En Java 8, je peux facilement écrire:
interface Interface1 {
default void method1() {
synchronized (this) {
// Something
}
}
static void method2() {
synchronized (Interface1.class) {
// Something
}
}
}
J'obtiendrai la sémantique de synchronisation complète que je pourrai également utiliser en classe. Je ne peux cependant pas utiliser le synchronized
modificateur sur les déclarations de méthode:
interface Interface2 {
default synchronized void method1() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
static synchronized void method2() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
}
Maintenant, on peut dire que les deux interfaces se comportent de la même manière , sauf que Interface2
établit un contrat sur method1()
et method2()
, ce qui est un peu plus fort que ce qui le Interface1
fait. Bien sûr, nous pourrions également affirmer que les default
implémentations ne devraient pas faire d'hypothèses sur l'état d'implémentation concret, ou qu'un tel mot clé ne pourrait tout simplement pas peser.
Question:
Quelle est la raison pour laquelle le groupe d'experts JSR-335 a décidé de ne pas prendre en charge synchronized
les méthodes d'interface?
la source
default synchronized
, mais pas nécessairement pourstatic synchronized
, bien que j'accepterais que ce dernier ait pu être omis pour des raisons de cohérence.synchronized
modificateur peut être remplacé dans les sous-classes, donc cela n'aurait d'importance que s'il y avait quelque chose comme méthodes par défaut finales. (Votre autre question)synchronized
dans les super classes, supprimant ainsi la synchronisation. Je ne serais pas surpris que le fait de ne pas soutenirsynchronized
et de ne pas soutenirfinal
soit lié, cependant, peut-être à cause de l'héritage multiple (par exemple, héritagevoid x()
etsynchronized void x()
, etc.). Mais c'est de la spéculation. Je suis curieux de connaître une raison faisant autorité, s'il y en a une.super
ce qui nécessite une réimplémentation complète et un accès possible aux membres privés. D'ailleurs, il y a une raison pour laquelle ces méthodes sont appelées «défenseurs» - elles sont présentes pour permettre d'ajouter plus facilement de nouvelles méthodes.Réponses:
Alors qu'au début, il peut sembler évident que l'on voudrait prendre en charge le
synchronized
modificateur sur les méthodes par défaut, il s'avère que cela serait dangereux et donc interdit.Les méthodes synchronisées sont un raccourci pour une méthode qui se comporte comme si le corps entier était enfermé dans un
synchronized
bloc dont l'objet de verrouillage est le récepteur. Il peut sembler judicieux d'étendre également cette sémantique aux méthodes par défaut; après tout, ce sont aussi des méthodes d'instance avec un récepteur. (Notez que lessynchronized
méthodes sont entièrement une optimisation syntaxique; elles ne sont pas nécessaires, elles sont juste plus compactes que lesynchronized
bloc correspondant . causer plus de problèmes qu'ils n'en résolvent, mais ce navire a navigué il y a longtemps.)Alors, pourquoi sont-ils dangereux? La synchronisation concerne le verrouillage. Le verrouillage consiste à coordonner l'accès partagé à un état mutable. Chaque objet doit avoir une politique de synchronisation qui détermine quels verrous gardent quelles variables d'état. (Voir Java Concurrency en pratique , section 2.4.)
De nombreux objets utilisent comme politique de synchronisation le modèle de moniteur Java (JCiP 4.1), dans lequel l'état d'un objet est protégé par son verrou intrinsèque. Il n'y a rien de magique ou de spécial dans ce modèle, mais c'est pratique, et l'utilisation du
synchronized
mot - clé sur les méthodes suppose implicitement ce modèle.C'est la classe qui possède l'état qui détermine la politique de synchronisation de cet objet. Mais les interfaces ne possèdent pas l'état des objets dans lesquels elles sont mélangées. Donc, l'utilisation d'une méthode synchronisée dans une interface suppose une politique de synchronisation particulière, mais que vous n'avez aucune base raisonnable pour supposer, il pourrait donc bien être le cas que l'utilisation de la synchronisation n'offre aucune sécurité supplémentaire sur les threads (vous synchronisez peut-être sur le mauvais verrou). Cela vous donnerait le faux sentiment de confiance que vous avez fait quelque chose à propos de la sécurité des threads, et aucun message d'erreur ne vous indique que vous supposez la mauvaise politique de synchronisation.
Il est déjà assez difficile de maintenir de manière cohérente une politique de synchronisation pour un seul fichier source; il est encore plus difficile de s'assurer qu'une sous-classe adhère correctement à la politique de synchronisation définie par sa super-classe. Essayer de le faire entre de telles classes à couplage lâche (une interface et les nombreuses classes qui l'implémentent) serait presque impossible et très sujet aux erreurs.
Compte tenu de tous ces arguments contre, quel serait l'argument? Il semble qu'ils visent principalement à faire en sorte que les interfaces se comportent davantage comme des traits. Bien que ce soit un désir compréhensible, le centre de conception pour les méthodes par défaut est l'évolution de l'interface, pas "Traits--". Là où les deux pouvaient être atteints de manière cohérente, nous nous sommes efforcés de le faire, mais là où l'un est en conflit avec l'autre, nous avons dû choisir en faveur de l'objectif de conception principal.
la source
synchronized
modificateur de méthode est apparu dans la sortie javadoc, induisant les gens en erreur en leur faisant croire qu'il faisait partie de la spécification. Cela a été corrigé dans JDK 1.2. Même s'il apparaît sur une méthode publique, lesynchronized
modificateur fait partie de l'implémentation, pas du contrat. (Un raisonnement et un traitement similaires ont éténative
appliqués au modificateur.)synchronized
composants sûrs threads et vous disposiez d'un programme presque sûr pour les threads. Le problème était que cela fonctionnait généralement bien, mais il s'est cassé de manière surprenante et fragile. Je suis d'accord que la compréhension du fonctionnement de votre verrouillage est la clé d'une application robuste.synchronized(this) {...}
autorisé dans unedefault
méthode? (Comme le montre la question de Lukas.) Cela ne permet-il pas à la méthode par défaut de posséder également l'état de la classe d'implémentation? Ne voulons-nous pas empêcher cela aussi? Aurons-nous besoin d'une règle FindBugs pour trouver les cas pour lesquels des développeurs non informés le font?synchronized(vector)
. Si vous voulez être en sécurité, vous ne devez jamais utiliser un objet public (tel quethis
lui-même) pour le verrouillage.résultat:
(désolé d'avoir utilisé la classe parent comme exemple)
d'après le résultat, nous pourrions savoir que le verrou de classe parent appartient à chaque sous-classe, les objets SonSync1 et SonSync2 ont un verrou d'objet différent. chaque serrure est indépendante. donc dans ce cas, je pense qu'il n'est pas dangereux d'utiliser un synchronisé dans une classe parent ou une interface commune. quelqu'un pourrait-il expliquer plus à ce sujet?
la source