0

I'm currently working on java application which has a scenario of multiple producers adding tasks to a queue and whenever queue is not empty tasks should be executed at predefined rate. (using multiple threads to maintain execution rate) After executing the available tasks executor has to wait till tasks available in the queue again.

I know blockingQueue can be used to triggering part in here and ScheduledExecutorService for execute tasks at fixed rate. But I could not find a way to link ability of both of this for my need. So I would be very thankful if you could give me any suggestion to make this happen.

  • What's the predefined rate at which the tasks should be executed if the task queue is non-empty? Would you not just want to execute the tasks as soon as you can? – rohitvats Aug 21 '16 at 17:03

2 Answers2

0

You need the task queue to be accessible by both the producer and consumer threads. I've written a basic program to demonstrate this, but I'll let you play around with the BlockingQueue API and the ScheduledExecutor as per your needs:

import java.util.concurrent.*;


public class ProducerConsumer {
    private static final BlockingQueue<Integer> taskQueue = new LinkedBlockingQueue<>();

    public static void main(String[] args) {
        ExecutorService consumers = Executors.newFixedThreadPool(3);
        consumers.submit(new Consumer());
        consumers.submit(new Consumer());
        consumers.submit(new Consumer());

        ExecutorService producers = Executors.newFixedThreadPool(2);
        producers.submit(new Producer(1));
        producers.submit(new Producer(2));
    }

    private static class Producer implements Runnable {
        private final int task;

        Producer(int task) {
            this.task = task;
        }

        @Override
        public void run() {
            System.out.println("Adding task: " + task);
            taskQueue.add(task); // put is better, since it will block if queue is full
        }
    }

    private static class Consumer implements Runnable {
        @Override
        public void run() {
            try {
                Integer task = taskQueue.take(); // block if there is no task available
                System.out.println("Executing task: " + task);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
rohitvats
  • 1,811
  • 13
  • 11
0

This is the way I could come up with as a solution. It looks little bit rusty but I have tested this and the code is working.

package test;

import java.util.concurrent.*;

public class FixedRateConsumer {

private BlockingQueue<String> queue = new ArrayBlockingQueue<>(20);

private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(5);

private boolean continueRunning = true;

public void executeInBackGraound() throws InterruptedException, ExecutionException {
    while (continueRunning) {
        String s = queue.take();
        Worker w = new Worker(s);
        ScheduledFuture future = executorService.scheduleAtFixedRate(w, 0, 1, TimeUnit.SECONDS);
        w.future = future;

        try {
            if (!future.isDone()) {
                future.get();
            }
        } catch (CancellationException e) {
            // Skipping
        }
    }
}

public void setContinueRunning(boolean state) {
    continueRunning = state;
}

public void addConsumableObject(String s) throws InterruptedException {
    queue.put(s);
}

private void consumeString(String s) {
    System.out.println("Consumed -> " + s + ", ... @ -> "  + System.currentTimeMillis() + " ms");
}

private class Worker implements Runnable {
    String consumableObject;
    ScheduledFuture future;

    public Worker(String initialConsumableObject) {
        this.consumableObject = initialConsumableObject;
    }

    @Override
    public void run() {
        try {
            if (consumableObject == null) {
                consumableObject = queue.take();
            }

            consumeString(consumableObject);

            consumableObject = null;
            if (queue.isEmpty()) {
                if (future == null) {
                    while (future == null) {
                        Thread.sleep(50);
                    }
                }

                future.cancel(false);
            }

        } catch (Exception e) {
            System.out.println("Exception : " + e);
        }
    }
}
}