user8920693
user8920693

Reputation: 95

ScheduledThreadPoolExecutor concurrent tasks

I have researched for this subject a lot but couldn't find any useful information. And I have decided to ask my first question on this platform. So, I am using a scheduled executor to repeat task in a specific period. Everything is fine. But there is a misunderstanding.... My code executes task but if task takes longer than schedule time then it waits to finish task and later starts execute new task. I want it to do that execute task when schedule time arrives and don't wait previous task to finish. How can I achieve this? I used SwingWorker on a swing project but this project is not a swing project. Thanks for reading.

Main method

        LogFactory.log(LogFactory.INFO_LEVEL, Config.MODULE_NAME + " - Available processors for Thread Pool: " + AVAILABLE_PROCESSORS);
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(AVAILABLE_PROCESSORS);
    LogFactory.log(LogFactory.INFO_LEVEL, Config.MODULE_NAME + " - [ScheduledExecutorService] instance created.");
    MainWorker task = new MainWorker();
    LogFactory.log(LogFactory.INFO_LEVEL, Config.MODULE_NAME + " - [Main worker] created...");
    executor.scheduleWithFixedDelay(task, 0, Config.CHECK_INTERVAL, TimeUnit.SECONDS);

Main Worker

public class MainWorker implements Runnable {

private final NIFIncomingController controller = new NIFIncomingController();

@Override
public void run() {
    LogFactory.log(LogFactory.INFO_LEVEL, Config.MODULE_NAME + " - [Task] executed - [" + Thread.currentThread().getName() + "]");
    controller.run();
}

}

Upvotes: 1

Views: 1519

Answers (2)

Advait Deodhar
Advait Deodhar

Reputation: 1

This can be achieved by using a single executor service. Say your schedule time is Y

  • Identify the time that can be taken by the task in worst case. Say X
  • If it is not in control, then control it in the task implementation to identify a timeout.
  • if X > Y, then create another task object and double up the schedule time
  • So the code may look like
executorService.schedule(taskObject1, 0/*Initial Delay*/, 2Y);
executorService.schedule(taskObject2, Y/*Initial Delay*/, 2Y);
  • If X > n(Y) then create n+1 tasks with scheduled time as (n+1)Y and initial delay as 0, 2Y, 3Y......(n-1)Y respectively.

Upvotes: 0

Pavel Ryzhov
Pavel Ryzhov

Reputation: 5142

You can try to combine several executors in order to achieve the desired behavior. Please, find an example code below:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


public class CombinedThreadPoolsExample {

    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    private static final int INITIAL_DELAY = 0;
    private static final int FIXED_DELAY_IN_MILLISECONDS = 1000;
    private static final int TASK_EXECUTION_IN_MILLISECONDS = FIXED_DELAY_IN_MILLISECONDS * 2;

    public static void main(String[] args) {
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        System.out.println("Available processors: [" + availableProcessors + "].");
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(availableProcessors);

        Runnable runnableThatTakesMoreTimeThanSpecifiedDelay = new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread name: [" + Thread.currentThread().getName() + "], time: [" + DATE_FORMAT.format(new Date()) + "].");
                try {
                    Thread.sleep(TASK_EXECUTION_IN_MILLISECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
        singleThreadScheduledExecutor.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                fixedThreadPool.execute(runnableThatTakesMoreTimeThanSpecifiedDelay);
            }
        }, INITIAL_DELAY, FIXED_DELAY_IN_MILLISECONDS, TimeUnit.MILLISECONDS);
    }
}

The first lines of the output are the following for my machine:

Available processors: [8].
Thread name: [pool-1-thread-1], time: [2017-12-25 11:22:00.103].
Thread name: [pool-1-thread-2], time: [2017-12-25 11:22:01.104].
Thread name: [pool-1-thread-3], time: [2017-12-25 11:22:02.105].
Thread name: [pool-1-thread-4], time: [2017-12-25 11:22:03.105].
Thread name: [pool-1-thread-5], time: [2017-12-25 11:22:04.106].
Thread name: [pool-1-thread-6], time: [2017-12-25 11:22:05.107].
Thread name: [pool-1-thread-7], time: [2017-12-25 11:22:06.107].
Thread name: [pool-1-thread-8], time: [2017-12-25 11:22:07.107].
Thread name: [pool-1-thread-1], time: [2017-12-25 11:22:08.108].
Thread name: [pool-1-thread-2], time: [2017-12-25 11:22:09.108].
Thread name: [pool-1-thread-3], time: [2017-12-25 11:22:10.108].
Thread name: [pool-1-thread-4], time: [2017-12-25 11:22:11.109].

However, beware of relying on such solution when a task execution can take a long time, compare to a pool size. Let's say we increase the time necessary for a task execution:

private static final int TASK_EXECUTION_IN_MILLISECONDS = FIXED_DELAY_IN_MILLISECONDS * 10;

This won't cause any exceptions during execution, but cannot enforce the specified delay between executions. It can be observed in the execution output after the aforementioned delay alteration:

Available processors: [8].
Thread name: [pool-1-thread-1], time: [2017-12-25 11:31:23.258].
Thread name: [pool-1-thread-2], time: [2017-12-25 11:31:24.260].
Thread name: [pool-1-thread-3], time: [2017-12-25 11:31:25.261].
Thread name: [pool-1-thread-4], time: [2017-12-25 11:31:26.262].
Thread name: [pool-1-thread-5], time: [2017-12-25 11:31:27.262].
Thread name: [pool-1-thread-6], time: [2017-12-25 11:31:28.263].
Thread name: [pool-1-thread-7], time: [2017-12-25 11:31:29.264].
Thread name: [pool-1-thread-8], time: [2017-12-25 11:31:30.264].
Thread name: [pool-1-thread-1], time: [2017-12-25 11:31:33.260].
Thread name: [pool-1-thread-2], time: [2017-12-25 11:31:34.261].
Thread name: [pool-1-thread-3], time: [2017-12-25 11:31:35.262].

Upvotes: 1

Related Questions