En Java 8, puedo escribir fácilmente:
interface Interface1 {
default void method1() {
synchronized (this) {
// Something
}
}
static void method2() {
synchronized (Interface1.class) {
// Something
}
}
}
Obtendré la semántica de sincronización completa que puedo usar también en las clases. Sin embargo, no puedo usar el synchronized
modificador en las declaraciones de método:
interface Interface2 {
default synchronized void method1() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
static synchronized void method2() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
}
Ahora, se puede argumentar que las dos interfaces se comportan de la misma manera excepto que Interface2
establece un contrato en method1()
y en method2()
, que es un poco más fuerte que lo Interface1
hace. Por supuesto, también podríamos argumentar que las default
implementaciones no deberían hacer suposiciones sobre el estado de implementación concreto, o que dicha palabra clave simplemente no aumentaría su peso.
Pregunta:
¿Cuál es la razón por la cual el grupo de expertos JSR-335 decidió no admitir los synchronized
métodos de interfaz?
java
java-8
synchronized
default-method
jsr335
Lukas Eder
fuente
fuente
default synchronized
, pero no necesariamentestatic synchronized
, aunque aceptaría que esta última podría haberse omitido por razones de coherencia.synchronized
modificador puede ser anulado en las subclases, por lo tanto, solo importaría si hubiera algo como métodos predeterminados finales. (Su otra pregunta)synchronized
en superclases, eliminando efectivamente la sincronización. Sin embargo, no me sorprendería que no admitirsynchronized
y no admitirfinal
esté relacionado, tal vez debido a la herencia múltiple (por ejemplo, herenciavoid x()
ysynchronized void x()
, etc.). Pero eso es especulación. Tengo curiosidad acerca de una razón autorizada, si hay una.super
que requiere una reimplementación completa y un posible acceso a miembros privados. Por cierto, hay una razón por la cual esos métodos se llaman "defensores": están presentes para permitir la adición de nuevos métodos más fácilmente.Respuestas:
Si bien al principio puede parecer obvio que uno desearía admitir el
synchronized
modificador en los métodos predeterminados, resulta que hacerlo sería peligroso, por lo que estaba prohibido.Los métodos sincronizados son una forma abreviada de un método que se comporta como si todo el cuerpo estuviera encerrado en un
synchronized
bloque cuyo objeto de bloqueo es el receptor. Puede parecer sensato extender esta semántica a los métodos predeterminados también; después de todo, también son métodos de instancia con un receptor. (Tenga en cuenta que lossynchronized
métodos son completamente una optimización sintáctica; no son necesarios, simplemente son más compactos que elsynchronized
bloque correspondiente . Hay un argumento razonable para afirmar que esta fue una optimización sintáctica prematura en primer lugar, y que los métodos sincronizados causan más problemas de los que resuelven, pero ese barco zarpó hace mucho tiempo).Entonces, ¿por qué son peligrosos? La sincronización se trata de bloquear. El bloqueo se trata de coordinar el acceso compartido al estado mutable. Cada objeto debe tener una política de sincronización que determine qué bloqueos protegen qué variables de estado. (Consulte Concurrencia de Java en la práctica , sección 2.4.)
Muchos objetos utilizan como política de sincronización el patrón de monitor de Java (JCiP 4.1), en el que el estado de un objeto está protegido por su bloqueo intrínseco. No hay nada mágico o especial en este patrón, pero es conveniente, y el uso de la
synchronized
palabra clave en los métodos asume implícitamente este patrón.Es la clase propietaria del estado que determina la política de sincronización de ese objeto. Pero las interfaces no poseen el estado de los objetos en los que se mezclan. Por lo tanto, el uso de un método sincronizado en una interfaz supone una política de sincronización particular, pero una que no tiene una base razonable para asumir, por lo que bien podría ser el caso de que El uso de la sincronización no proporciona seguridad adicional para subprocesos (es posible que esté sincronizando en el bloqueo incorrecto). Esto le daría la falsa sensación de confianza de que ha hecho algo sobre la seguridad de los subprocesos, y ningún mensaje de error le indica que está asumiendo una política de sincronización incorrecta.
Ya es bastante difícil mantener consistentemente una política de sincronización para un solo archivo fuente; es aún más difícil asegurarse de que una subclase se adhiera correctamente a la política de sincronización definida por su superclase. Intentar hacerlo entre esas clases poco acopladas (una interfaz y posiblemente las muchas clases que lo implementan) sería casi imposible y altamente propenso a errores.
Teniendo en cuenta todos esos argumentos en contra, ¿cuál sería el argumento? Parece que se trata principalmente de hacer que las interfaces se comporten más como rasgos. Si bien este es un deseo comprensible, el centro de diseño para los métodos predeterminados es la evolución de la interfaz, no "Rasgos-". Donde los dos podrían lograrse de manera consistente, nos esforzamos por hacerlo, pero donde uno está en conflicto con el otro, tuvimos que elegir a favor del objetivo de diseño primario.
fuente
synchronized
modificador de método apareció en la salida de javadoc, engañando a la gente a pensar que era parte de la especificación. Esto se solucionó en JDK 1.2. Incluso si aparece en un método público, elsynchronized
modificador es parte de la implementación, no del contrato. (Razonamiento y tratamiento similares ocurrieron para elnative
modificador).synchronized
y usar componentes seguros para subprocesos y usted tenía un programa casi seguro para subprocesos. El problema era que esto generalmente funcionaba bien, pero se rompió de manera sorprendente y frágil. Estoy de acuerdo en que entender cómo funciona su bloqueo es clave para aplicaciones robustas.synchronized(this) {...}
permitido en undefault
método? (Como se muestra en la pregunta de Lukas). ¿Eso no permite que el método predeterminado también sea dueño del estado de la clase de implementación? ¿No queremos evitar eso también? ¿Necesitaremos una regla FindBugs para encontrar los casos en que los desarrolladores desinformados hacen eso?synchronized(vector)
. Si desea estar seguro, nunca debe usar un objeto público (como élthis
mismo) para bloquear.resultado:
(perdón por usar la clase padre como ejemplo)
a partir del resultado, podríamos saber que el bloqueo de la clase principal es propiedad de cada subclase, SonSync1 y SonSync2 tienen un bloqueo de objeto diferente. cada cerradura es independencia. así que en este caso, creo que no es peligroso usar un sincronizado en una clase principal o una interfaz común. ¿Alguien podría explicar más sobre esto?
fuente