2010-08-21 14 views
42

En NetBeans, hay una nueva sugerencia que dice: Thread.sleep llamado en bucle.NetBeans/Java/Nueva pista: Thread.sleep llamado en el bucle

Pregunta 1: ¿Cómo/cuándo puede ser un problema dormir en un bucle?

Pregunta 2: Si es un problema, ¿qué debo hacer en su lugar?

ACTUALIZACIÓN: Pregunta 3: Aquí hay algunos códigos. Dime en este caso si debería usar algo más en lugar de Thread.Sleep en un bucle. En resumen, esto es utilizado por un servidor que escucha las conexiones TCP del cliente. La suspensión se usa aquí en caso de que se alcance el número máximo de sesiones con los clientes. En esta situación, quiero que la aplicación espere hasta que esté disponible una sesión gratuita.

public class SessionManager { 
    private static final int DEFAULT_PORT = 7500; 
    private static final int SLEEP_TIME = 200; 
    private final DatabaseManager database = new DatabaseManager(); 
    private final ServerSocket serverSocket = new ServerSocket(DEFAULT_PORT); 

public SessionManager() throws IOException, SQLException 
{ 
} 

public void listen() 
{ 
while (true) 
    if (Session.getSessionCount() < Session.getMaxSessionCount()) 
     try 
     { 
      new Thread(new Session(database, serverSocket.accept())).start(); 
     } 
     catch (IOException ex) { ex.printStackTrace(); } 
    else 
     try 
     { 
      Thread.sleep(SLEEP_TIME); 
     } 
     catch (InterruptedException ex) { ex.printStackTrace(); } 
} 

public static void main(String[] args) throws IOException, SQLException 
{ 
new SessionManager().listen(); 
} 
} 

Respuesta

19

Llamar a dormir en un bucle generalmente conduce a un rendimiento pobre. Por ejemplo:

while (true) { 
    if (stream.available() > 0) { 
     // read input 
    } 
    sleep(MILLISECONDS); 
} 

Si milisegundos es demasiado grande, entonces este código va a tomar mucho tiempo para darse cuenta de que la entrada está disponible.

Si MILLISECONDS es demasiado pequeño, este código desperdiciará una gran cantidad de recursos del sistema, compruebe la entrada que aún no ha llegado.

Otros usos de sleep en un ciclo son generalmente cuestionables también. Usualmente hay una mejor manera.

Si es un problema, ¿qué debo hacer en su lugar?

Publique el código y quizás podamos darle una respuesta sensata.

EDITAR

OMI, una mejor manera de resolver el problema es utilizar un ThreadPoolExecutor.

Algo como esto:

public void listen() { 
    BlockingQueue queue = new SynchronousQueue(); 
    ThreadPoolExecutor executor = new ThreadPoolExecutor(
      1, Session.getMaxSessionCount(), 100, TimeUnit.SECONDS, queue); 
    while (true) { 
     try { 
      queue.submit(new Session(database, serverSocket.accept())); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 
    } 
} 

Esto configura el ejecutor para que coincida con la forma en que el código funciona actualmente. Hay otras maneras en que podrías hacerlo; ver el enlace javadoc arriba.

+0

¿Qué tal un java.util.Timer y TimerTask periódico? – Core

+0

@ Core: depende de cómo lo use. Si solo lo usa para implementar el equivalente de 'sleep()', tiene los mismos problemas que con 'sleep()'. –

+0

¿y si usamos managedexecutorservice? – wib

2

Cómo/cuándo puede ser un problema para dormir en un bucle?
Las personas a veces lo emplean en lugar de los métodos de sincronización adecuados (como wait/notify).

Si es un problema, ¿qué debo hacer en su lugar?
Depende de lo que esté haciendo. Aunque es difícil para mí imaginar una situación en la que hacer esto sea el mejor enfoque, creo que eso también es posible.

Puede consultar sobre este tema.

+0

Las personas también utilizan a veces por un bucle de lectura en conjunto con las pruebas disponibles(), cuando sólo deberían estar bloqueando la lectura en lugar de perder el tiempo y el espacio. – EJP

+0

Un uso es un limpiador de directorios, que elimina archivos anteriores a un cierto período. Después de la primera ejecución, sabemos cuál es el archivo más antiguo, y exactamente cuánto tiempo hasta que llegue a ser "demasiado viejo", por lo que podemos dormir durante ese período. – Jesse

+0

@Jesse - un ejecutor de grupo de subprocesos programado probablemente sería mejor para eso. –

3

Como han dicho otros, depende del uso.Un uso legítimo sería un programa que está diseñado para hacer algo cada 10 segundos (pero no es tan crítico que se requiera el tiempo exacto). Tenemos muchas de estas "aplicaciones de utilidad" que importan datos y otras tareas similares cada pocos minutos. Esta es una manera fácil de realizar estas tareas y, por lo general, estableceremos que el intervalo de sueño sea muy bajo y usemos un contador para que el programa se mantenga receptivo y pueda salir fácilmente.

int count = 0; 
while (true) { 

    try { 
     // Wait for 1 second. 
     Thread.sleep(1000); 
    } 
    catch (InterruptedException ex) {} 

    // Check to see if the program should exit due to other conditions. 
    if (shouldExit()) 
     break; 

    // Is 10 seconds up yet? If not, just loop back around. 
    count++; 
    if (count < 10) continue; 

    // 10 seconds is up. Reset the counter and do something important. 
    count = 0; 
    this.doSomething(); 
} 
+1

En su lugar, usar un ejecutor de agrupaciones de hilos programado sería técnicamente mejor en la mayoría de los casos, pero a veces es demasiado cuando se está programando algo rápido y sucio. – mjaggard

+0

@mjaggard digamos que actualmente tengo un hilo con un bucle con un sueño adentro. Está haciendo tareas domésticas, como purgar datos antiguos que ya no son relevantes. El uso de un ejecutor de grupo de subprocesos programado agregaría complejidad innecesaria al código, en comparación con el hecho de tener un hilo de larga duración, mayormente inactivo. La penalización de cambio de contexto es insignificante para un hilo de larga duración/inactivo que está durmiendo. ¿Qué le compra realmente un Pool de hilos programado, aparte de eliminar la advertencia "no es una buena práctica"? – ruckc

+2

¿Has escrito el código para cada uno? Sospecho que la versión del ejecutor del pool de subprocesos programado podría ser más corta, más fácil de leer y una eficiencia muy similar. – mjaggard

1

creo que me encuentro con un uso completamente legítimo de sleep() método en el bucle.

Tenemos una conexión de una vía entre el servidor y el cliente. Entonces, cuando el cliente desea lograr una comunicación asíncrona con el servidor, envía un mensaje al servidor y luego periódicamente busca alguna respuesta del servidor. Debe haber algún intervalo de tiempo de espera.

Response resp = null; 
for (int i = 0; i < POLL_REPEAT && resp == null; i++) { 
    try { 
     Thread.sleep(POLL_INTERVAL); 
    } catch (InterruptedException ie) { 
    } 
    resp = server.getResponse(workflowId); 
} 

POLL_REPEAT * POLL_INTERVAL ~ intervalo de espera

+1

Una mejor solución si es posible con su API sería utilizar un método IO de bloqueo, que espera hasta el momento en que los nuevos datos estén disponibles. – Vitruvius