Amriteya
Amriteya

Reputation: 1182

Controlled ThreadPoolExecutor in Java Spring

I need to create a global ThreadPoolTaskExecutor in my Spring application which will be responsible for running multi-threaded tasks in my application.

However, for every request I want to limit the number of threads used from that global ThreadPool. How should I ensure that this restriction, per request, is enforced?

For eg.

I create a global thread-pool with max pool size as 50 threads. But I want to limit the number of threads per Request to say 5 threads. But these 5 threads could only be allocated from the 50 threads available in global thread pool defined in Configuration file.

Configuration class for creating the task executor.

@Configuration
public class ThreadPoolConfiguration {

    @Value("${threadpool.corepoolsize}")
    int corePoolSize;

    @Value("${threadpool.maxpoolsize}")
    int maxPoolSize;

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setCorePoolSize(corePoolSize);
        pool.setMaxPoolSize(maxPoolSize);
        pool.setWaitForTasksToCompleteOnShutdown(true);
        return pool;
    }
}

Controller class

@RestController
public class WebController {

    @Autowired
    ThreadPoolTaskExecutor threadPool;

    @RequestMapping("/process")
    public String process(){

        String msg = "";
        List<Future<String>> futureList = new ArrayList<>();
        for(int threadNumber = 0; threadNumber < 5; threadNumber ++){
            CallableWorker callableTask = new CallableWorker(String.valueOf(threadNumber));
            Future<String> result = threadPool.submit(callableTask);
            futureList.add(result);
        }

        for(Future<String> future: futureList){
            try {
                msg += future.get() + "#####";
            } catch (Exception e){}
        }

        return msg;
    }
}

Disclaimer: This is just sample code I got from a blog post.

How can I implement such a design? I don't see any sub thread pool which can be created. Neither do I want to instantiate a thread pool for every request as that would be catastrophic.

Any suggestion?

Upvotes: 3

Views: 3890

Answers (2)

Warren Dew
Warren Dew

Reputation: 8938

The way I would do this would be to create a class that would throttle the tasks. Each request would create a throttle and submit all its tasks to the throttle; the throttle would submit the first 5 (say) tasks to the Executor and put the others on a list. As submitted tasks were completed, additional tasks could be submitted.

To determine when tasks were completed, the throttle could either poll the submitted tasks periodically, checking the Futures' isDone() method to see if they were done, or it could block on one Future's get() method until it was done and check on the other pending futures at that point, or if you wanted to get sophisticated, the request thread could wait() on the throttle and the tasks could be set up to notify() the throttle on completion so the request thread would then wake up and and check for completed tasks.

Upvotes: 1

Abhilash Panigrahi
Abhilash Panigrahi

Reputation: 1525

One way of solving this could be creating your callable methods to work on a list of elements instead of single elements.

For example, if you want to delete x items in a request, you can create lists of x/5 elements and pass this list to your callable function. This way, through code, you can ensure that at most only 5 threads will be utilized per request. You'll have to handle the exception scenarios with care though. (for e.g. you can return a Map of elementID to result enum, where result could be success, retryable excepiton or non retryable exception.)

This approach may vary depending on what exactly you are trying to achieve.

Upvotes: 1

Related Questions