2010-11-15 8 views
17

que tienen un hilo que se ejecuta el código siguiente:¿Cómo detener un hilo esperando en una operación de bloqueo de lectura en Java?

public void run() { 
    try { 
     int n = 0; 
     byte[] buffer = new byte[4096]; 
     while ((n = in.read(buffer)) != -1) { 
      out.write(buffer, 0, n); 
      out.flush(); 
     } 
    } catch (IOException e) { 
     System.out.println(e); 
    } 
} 

donde in es System.in. ¿Cómo puedo detener dicho hilo con gracia? Ni cerrando System.in, ni usando Thread.interrupt parecen funcionar.

+1

¿Qué sucede cuando usas la interrupción? –

+0

@tulskiy: el hilo continúa ejecutándose hasta que Ctrl-D (EOF) se ingrese manualmente. – vitaut

Respuesta

7

Esto es porque leer System.in (InputStream) es una operación de bloqueo.

mira aquí Is it possible to read from a InputStream with a timeout?

+1

Gracias. Usando NIO 'FileChannel' extraído de' System.in' permite detener el hilo simplemente cerrando 'System.in'. El cierre de 'System.in' da como resultado' AsynchronousCloseException' que interrumpe el bloqueo 'FileChannel.read'. – vitaut

2

Se puede utilizar el método disponible() (que es no-bloqueo) para comprobar si hay algo para leer de antemano.

En pseudo-java:

//... 
while(running) 
{ 
    if(in.available() > 0) 
    { 
     n = in.read(buffer); 
     //do stuff with the buffer 
    } 
    else 
    { 
     Thread.sleep(500); 
    } 
} 
//when running set to false exit gracefully here... 
+1

Esperando 0.5 segundos - ¿eso no parece correcto? – dacwe

+1

Número abreviado, si no duerme, termina en un bucle que hace girar la CPU esperando que se lean los bytes disponibles. Mi suposición era que este hilo pasará la mayor parte del tiempo esperando la entrada. – Paolo

+0

Usar 'available' casi hace el truco. El problema es que en el caso de EOF 'available' devuelve 0 y el hilo continúa la ejecución. +1 para compensar por injusto -1 =) – vitaut

-3

se puede utilizar un indicador externo para este

boolean flag = true; 


public void run() { 
    try { 
     int n = 0; 
     byte[] buffer = new byte[4096]; 
     while ((n = in.read(buffer)) != -1 && flag) { 
      out.write(buffer, 0, n); 
      out.flush(); 
     } 
    } catch (IOException e) { 
     System.out.println(e); 
    } 
} 
+3

Sin embargo, eso no interrumpirá una llamada ya bloqueada, por lo que no soluciona el problema. –

0

Si desea dar a un usuario un tiempo para introducir datos - tal vez para permitir anular valores predeterminados o interrumpir algún proceso automatizado -, luego espere primero y verifique la entrada disponible después de la pausa:

System.out.println("Enter value+ENTER within 5 Seconds to override default value: "); 
try{ 
    Thread.sleep(5000); 
} catch {InterruptedException e){} 

try{ 
    int bytes = System.in.available(); 
    if (bytes > 0) { 
    System.out.println("Using user entered data ("+size+" bytes)"); 
    } else { 
    System.out.println("Using default value"); 
    } 
} catch(IOException e) { /*handle*/ } 
6

Te has encontrado con un niño de 9 años bug que nadie está dispuesto a arreglar. Dicen que hay algunas soluciones en this bug report. Lo más probable es que necesite encontrar otra forma de establecer el tiempo de espera (la espera ocupada parece inevitable).

1

que tenían el mismo problema hoy en día, y así es como me fijo, utilizando in.ready():

public void run() { 
    String line; 
    // Some code 

    while(!Thread.currentThread().isInterrupted()){ 
     try { 
      if (in.ready()) { 
       line = in.readLine(); 
      } 
     } catch (Exception e) { 
      try { 
       Thread.currentThread().wait(500); 
      } catch (InterruptedException e1) { 
       // Do what we want when thread is interrupted 
      } 
     } 
    } 
} 
+0

Interesante, pero ¿no está tomando mucha CPU ejecutando el ciclo todo el tiempo mientras no hay nada que leer? – vitaut

+0

En realidad, esa es la razón por la que hice que el hilo espere un tiempo cada iteración. Pero tienes razón, no es tan eficiente como podría ser. Depende ahora de cuál es el propósito del software. – Nans

+1

Bastante seguro de que esto aún se cuelga si no hay una nueva línea en la transmisión. in.ready() devuelve verdadero si hay un solo byte, en.readLine() lo lee y luego sigue esperando (para siempre) la nueva línea. – pendor

1

¿Es seguro para cerrar en secuencia en otro hilo? Funciona para mí. En este caso, in.read(...) arroja la excepción SocketException.

Cuestiones relacionadas