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 synchronizedmodificador 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 Interface2establece un contrato en method1()y en method2(), que es un poco más fuerte que lo Interface1hace. Por supuesto, también podríamos argumentar que las defaultimplementaciones 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 synchronizedmé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.synchronizedmodificador puede ser anulado en las subclases, por lo tanto, solo importaría si hubiera algo como métodos predeterminados finales. (Su otra pregunta)synchronizeden superclases, eliminando efectivamente la sincronización. Sin embargo, no me sorprendería que no admitirsynchronizedy no admitirfinalesté 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.superque 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
synchronizedmodificador 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
synchronizedbloque 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 lossynchronizedmétodos son completamente una optimización sintáctica; no son necesarios, simplemente son más compactos que elsynchronizedbloque 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
synchronizedpalabra 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
synchronizedmodificador 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, elsynchronizedmodificador es parte de la implementación, no del contrato. (Razonamiento y tratamiento similares ocurrieron para elnativemodificador).synchronizedy 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 undefaultmé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 élthismismo) 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