Java how to avoid using Thread.sleep() in a loop

Instead of making Consumer extend Runnable you could change your code to incorporate a ScheduledExecutorService which runs the polling of the queue every half a second instead of making the thread sleep. An example of this would be

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);
}

The proper solution to your problem is to use a blocking queue. It gives you several advantages:

  • does not waste cpu busy waiting
  • can have limited capacity - imagine you have a fast producer, but a slow consumer -> if the queue is not limited in size, then your application can easily reach OutOfMemory condition

Here is a small demo, which you can play with:

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

public class ProdConsTest {
    public static void main(String[] args) throws InterruptedException {
        final BlockingQueue<Integer> 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();
    }
}

Now uncomment the sleep() in the consumer and observe what happems with the application. If you were using a timer based solution such as the proposed ScheduledExecutorService or you were busy waiting, then with fast producer, the queue would grow uncontrollably and eventually crash your application


Let the consumer wait() on an object that both have access to, and let the producer notify() listeners on this object when there's new messages. The consumer should remove all messages then, not just a single one like in the example.