viernes, 19 de octubre de 2012

Método Deprecados (Desaconsejados) - Threads -

El método stop(), que ocasiona el lanzamiento de la excepción ThreadDeath en el thread destino. La excepción se genera sea cual sea el método que está ejecutando el thread. La idea es que la excepción no se capture, de modo que vaya subiendo en la pila de llamadas de el thread destino, hasta llegar al método run(), que tampoco la capturaría, finalizando la ejecución de el Thread. La excepción ThreadDeath es la única que es ignorada por el método uncaughtException(...) de la clase ThreadGroup, de modo que el usuario no recibe ningún mensaje en la salida de error por culpa de dicha excepción.
        ThreadDeath hereda intencionadamente de Error, en lugar de Exception, pues lo que se quiere es que no sea capturada, y como existe el uso generalizado de la construcción:

    try {
       ...
    }
    catch (Exception e) {
       ...
    }


         prefirieron que ThreadDeath no heredara de Exception, a pesar de que no entra dentro de la filosofía de la clase Error.



         Una versión más general del método stop() es el método stop(Throwable), que ocasiona el lanzamiento de la excepción especificada como parámetro. Por tanto, stop() es equivalente a stop(new ThreadDeath());.

        Ambos métodos están desaconsejados porque son peligrosos. La generación de la excepción puede aparecer en cualquier momento, incluso en momentos críticos en los que el código no está preparado. Por ejemplo, es posible que salte dentro de un método sincronizado. La excepción ocasionará la finalización abrupta del método, lo que podría ocasionar que el objeto se quedara en un estado incorrecto, que podría ser visto por otros hilos, volviendo al sistema inestable.
        Naturalmente una posible solución sería que en todos los métodos sincronizados o que peligran ante la aparición de la excepción la capturaran, realizaran una limpieza rápida, y luego volvieran a generar la misma excepción, para que se propague y el Thread termine.
        Esta solución sin embargo es peligrosa, pues es fácil que el programador olvide realizar el control. Más aún, podría darse el caso de que una segunda excepción ThreadDeath saltara cuando se estaba tratando la primera, en cuyo caso el método saldría abruptamente antes de realizar la limpieza.

        Una solución más aceptada es la utilización de una variable que indica a el Thread si debe detener su ejecución:

void run() {
    while(!acabar) {
       ...
    }
}

/**
 * Sustituto de stop();
 */
void acabar() {
    acabar = true;
}


        Para que el Thread responda de forma fluida, debería comprobar a menudo el valor de la variable acabar.

         Un peligro añadido del método stop(Throwable) es que puede ocasionar que un método propague una excepción sin que el compilador pueda comprobarla. Por ejemplo:

void excepcionOculta() {
    Thread.currentThread.stop(new MiExepcion());
}


         El método excepcionOculta() ocasiona la propagación de una excepción (que no heredaría ni de Error ni de RuntimeException) y que el compilador no puede controlar, es decir no puede forzar a los programadores a que capturen la excepción en los lugares donde se llame al método (como haría si se lanzara con throw), pues no es consciente de ese lanzamiento. Esto rompe con toda la filosofía del compilador de forzar al programador a controlar los errores.

         Por otro lado, el método suspend() detiene el Thread hasta que se llama a resume() del mismo hilo. También están desaconsejados. Eso se debe a que suspend() no libera el cerrojo del objeto si es llamado dentro de un método sincronizado. Por tanto el uso de suspend() y de resume() dentro de un mismo objeto sincronizado ocasiona la aparición de interbloqueo.
  
        El último es el método destroy(), que es el más radical de todos. Su llamada ocasiona la destrucción completa del Thread, sin liberar ninguno de los cerrojos que tuviera bloqueados. Debido a su claro peligro, no está implementado. El JDK lo documenta, pero no hace nada. Curiosamente, está desaconsejado su uso (¡aunque no hace nada!), pues se comportaría igual que un suspend() sin resume().

No hay comentarios:

Publicar un comentario