Saltar al contenido

Java cómo evitar el uso de Thread.sleep() en un bucle

Comprende el código correctamente previamente a adaptarlo a tu proyecto si tquieres aportar algo puedes dejarlo en la sección de comentarios.

Solución:

La solución adecuada a su problema es utilizar una cola de bloqueo. Te da varias ventajas:

  • no desperdicia la CPU ocupada esperando
  • puede tener una capacidad limitada: imagine que tiene un productor rápido, pero un consumidor lento -> si la cola no tiene un tamaño limitado, entonces su aplicación puede alcanzar fácilmente la condición OutOfMemory

Aquí hay una pequeña demostración con la que puedes jugar:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ProdConsTest 
    public static void main(String[] args) throws InterruptedException 
        final BlockingQueue queue = new ArrayBlockingQueue<>(10);
        final Runnable producer = () -> 
            for (int i = 0; i < 1000; i++) 
                try 
                    System.out.println("Producing: " + i);
                    queue.put(i);

                    //Adjust production speed by modifying the sleep time
                    Thread.sleep(100);
                 catch (InterruptedException e) 
                    //someone signaled us to terminate
                    break;
                
            
        ;

        final Runnable consumer = () -> 
            while (true) 
                final Integer integer;
                try 
                    //Uncomment to simulate slow consumer:
                    //Thread.sleep(1000);

                    integer = queue.take();
                 catch (InterruptedException e) 
                    //someone signaled us to terminate
                    break;
                
                System.out.println("Consumed: " + integer);
            
        ;


        final Thread consumerThread = new Thread(consumer);
        consumerThread.start();

        final Thread producerThread = new Thread(producer);
        producerThread.start();

        producerThread.join();
        consumerThread.interrupt();
        consumerThread.join();
    

Ahora descomente el sleep() en el consumidor y observar lo que ocurre con la aplicación. Si estuviera usando una solución basada en un temporizador como la propuesta ScheduledExecutorService o estabas ocupado esperando, luego con el productor rápido, la cola crecería sin control y eventualmente colapsaría tu aplicación

En lugar de hacer Consumidor extend Runnable podrías cambiar tu código para incorporar un ScheduledExecutorService que ejecuta el sondeo de la cola cada medio segundo en lugar de hacer que el hilo duerma. Un ejemplo de esto seria

public void schedule() 
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    executor.scheduleAtFixedRate(() -> 
        String str;
        try 
            while ((str = queue.poll()) != null) 
                call(str);  // do further processing
            
         catch (IOException e) 
            ferpt.felog("svr class", "consumer", "consumer thread", e.getClass().getName() + ": " + e.getMessage());
        
    , 0, 500, TimeUnit.MILLISECONDS);

Aquí tienes las comentarios y valoraciones

Tienes la opción de amparar nuestra faena escribiendo un comentario o dejando una valoración te damos las gracias.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *