¿Por qué Thread no es una clase abstracta y start () no es final?

79

¿Por qué la Threadclase se implementó como una clase regular y no como una clase abstracta con un run()método abstracto?

¿Posiblemente introducirá algún problema? ¿O tiene alguna utilidad en ser así?

Además, Thread.start()se supone que el método es un método muy específico cuya funcionalidad no puede ser implementada por ninguna otra clase (si no me equivoco). Y, por lo tanto, supongo que la finalpalabra clave sería apta para esto más que cualquier otro método.

Pero puedo anular este método y usarlo como quiera,

public class Test extends Thread {
    public static void main (String... args) {
        Thread test = new Test();
        test.start();
    }

    @Override
    public void run() {
        System.out.println("New thread started...");
    }

    @Override
    public void start() {
        System.out.println("Did anyone tell you I will spawn a new thread??");
    }
}

Obviamente solo imprimió,

¿Alguien te dijo que generaré un nuevo hilo?

¿Tiene algún uso anular que no sea confundir al ingeniero que lo reemplaza?

Si no es así, ¿por qué el método no se declaró final en la clase Thread?

Codebender
fuente
Aquí está llamando al método start como miembro de la clase ... no se llama desde el planificador ...
CoderNeji
2
Para mayor claridad, se pregunta por qué Thread.run () no es abstracto, ya que los usuarios deben anularlo, y por qué Thread.start () no es final, ya que no tiene ningún sentido anularlo. ¡Buena pregunta! Me doy cuenta de que alguien ha votado negativamente, me pregunto por qué.
NickJ
3
Preferiría que la Threadclase fuera definitiva. El constructor ya toma un ejecutable, por lo que no se necesita herencia para crear un hilo.
derecha

Respuestas:

50

¿Por qué se implementó la clase Thread como una clase regular y no como una clase abstracta con el método run () siendo abstracto?

En realidad, esta pregunta se reduce al hecho de que siempre debe preferir la composición a la herencia.

Si la Threadclase se declarara como abstract, el lenguaje tendría que proporcionar otra clase que se extendiera a partir de ella y que los programadores pudieran usar para crear un Thread. Su pregunta sería entonces acerca de por qué esta clase extendsde Threadno lo es abstract. Si el lenguaje no proporcionó otra clase extendsdesde Thread, los programadores tendrían que crear su propia clase a extendpartir de Thready anular el run()método.

Si no es así, ¿por qué el método no se declaró final en la clase Thread?

La única explicación posible que puedo dar es que los desarrolladores del lenguaje vieron algunos casos de uso para anular startcuando se introdujo la clase en el JDK. La primera versión de Java que utilicé fue 1.5 y personalmente no me he encontrado con un caso de uso en el que haya encontrado la necesidad de anular start. Como dijo JB Nizet en su respuesta

si Java se rediseñó desde cero hoy, es muy probable que el diseño sea diferente

CKing
fuente
1
Aunque no tiene que extender la clase Thread para nombrar el hilo (solo llamar a Thread.setName () sería suficiente), la parte que explica por qué la clase no puede ser abstracta es muy clara y precisa ...
Codebender
@Codebender estuvo de acuerdo. He eliminado eso de mi respuesta porque no era un buen ejemplo y también porque su pregunta no preguntaba Cuándo extender el hilo.
CKing
Es un diseño limpio; ¿Por qué sería diferente hoy?
Warren Dew
76

Por supuesto, puedes optar por dispararte en el pie, pero eso no significa que debas hacerlo.

¿Por qué se implementó la clase Thread como una clase regular y no como una clase abstracta con el método run () siendo abstracto?

Porque la forma recomendada de crear un inicio de un hilo es no subclase de hilo. La forma recomendada es definir a Runnabley pasarlo como argumento al constructor de Thread:

Runnable r = new Runnable() {
    @Override
    public void run() {
        ...
    }
};
Thread t = new Thread(r);
t.start();

Y, por lo tanto, supongo que la palabra clave final sería apta para esto más que cualquier otro método.

Si y no. No puede reemplazar la implementación de start () por su propia implementación, pero puede hacer cosas adicionales en start () si lo desea:

@Override
public void start() {
    System.out.println("Did anyone tell you I will spawn a new thread??");
    super.start();
}

Dicho esto, si Java se rediseñara desde cero hoy en día, es muy probable que el diseño sea diferente. Recuerde que esta clase data de Java 1.0 y aún es compatible con versiones anteriores.

JB Nizet
fuente
Te he citado en mi respuesta. Espero que esté bien para usted :)
CKing
11
No hay problema. Es de código abierto.
JB Nizet
2
@NayukiMinase no. Las interfaces siempre han estado en el idioma. Runnable existe desde JDK 1.0.
JB Nizet
Vaya, me confundí con cómo se introdujo en 1.1 un nuevo sistema de manejo de eventos AWT basado en devoluciones de llamada de interfaz (en lugar de anulación de métodos).
Nayuki
1
El hilo tiene un diseño limpio; ¿Por qué sería diferente hoy?
Warren Dew
40

¿Por qué Thread.start()no lo es final?

¿Estás seguro de que nunca querrás anularlo?

Class MyThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r) {
            @Override
            public void start() {
                LOGGER.info("Starting thread " + this);
                super.start();
            }
        };
    }
}
Salomón lento
fuente
0

Siento que se deben publicar algunas calirifcaciones para las respuestas:

"¿Estás seguro de que nunca querrás anularlo?"

No ! Yo no lo haría. Es como decir: "¿Estás seguro de que quieres declarar privada esta variable?" Porque si pudiera declarar pública cualquier variable que uso sin temer que otros desarrolladores puedan estropear mi lógica de diseño, la codificación sería muy sencilla. Uno de los propósitos más importantes de los conceptos de OOPS de alcance, abstracción, polimorfismo, manejo de errores, etc. es comunicar a otros desarrolladores el diseño y las intenciones detrás de su código.Como se señaló en la pregunta, cuando anula el método de inicio, nadie lo está forzando para usar super.start (). @Codebender escribió un método de inicio para un hilo sin usar super.start () y el compilador nunca se quejó. Entonces, ¿es libre de romper todo el mecanismo de Threading y se supone que el compilador debe dejarlo pasar? El método de inicio de Thread asegura que el método de ejecución sea llamado y ejecutado en el momento adecuado. Es fundamental para el concepto mismo de Threading. Estaría más que feliz de ser corregido, si me perdiera algo aquí. 2.

Porque la forma recomendada de crear un inicio de un hilo es no subclase de hilo.

Bien, si codebender está permitido por diseño, subclasear Thread y estropear el método de inicio, según esa lógica, es el diseño el que se dispara en el pie. Por otra declaración hecha, (con la que estoy completamente de acuerdo), Runnable es la forma recomendada. Entonces, ¿por qué permitimos que la clase Thread cree una instancia del hilo sin restricciones? A esto le sigue:

No puede reemplazar la implementación de start () por su propia implementación,

Eso en realidad respalda la afirmación de Codebender de que el método de inicio debería ser definitivo cuando dices eso .. ^

El único punto, que es válido, ya se menciona como nota al margen, pero es la respuesta real a esta pregunta.

"Compatibilidad con versiones anteriores".

De hecho, las mejoras se produjeron incluso hasta JDK 5.0, cuando incorporaron muchas adiciones y aclaraciones importantes al modelo de concurrencia de Java. Queremos que la compatibilidad con versiones anteriores sea compatible en todo momento y es por eso que la clase Thread sigue siendo exactamente como era antes, a pesar de que la interfaz Runnable es la forma recomendada hoy en día.

Una vez más, estaría más que feliz de ser corregido, si me perdiera algo.

Utkarsh Srivastava
fuente