简体   繁体   中英

How to run multiple threads of the same process in Java - Spring Boot

I have a scheduled task which needs to launch multiple threads of the same process when executed, is it possible to set a specific number of threads to be launched when the process is kicked off?

In the application class I have the following TaskExecutor beans configured

    @Bean("threadFooExecutor")
    public TaskExecutor getFooExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(1000);
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setThreadNamePrefix("Foo-");
        return executor;
    }```

    @Bean("threadBarExecutor")
    public TaskExecutor getBarExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(1000);
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setThreadNamePrefix("Bar-");
        return executor;
    }

Async processes configured in process class

    @Async("threadFooExecutor")
    @Scheduled(fixedRate = 3000, initialDelay = 5000)
    public void print() {
        System.out.println(Thread.currentThread().getName() + " " + 1);
        System.out.println(Thread.currentThread().getName() + " " + 2);
        System.out.println(Thread.currentThread().getName() + " " + 3);
        System.out.println(Thread.currentThread().getName() + " " + 4);
    }

    @Async("threadBarExecutor")
    @Scheduled(fixedRate = 3000, initialDelay = 5000)
    public void print2() {
        System.out.println(Thread.currentThread().getName() + " " + 1);
        System.out.println(Thread.currentThread().getName() + " " + 2);
        System.out.println(Thread.currentThread().getName() + " " + 3);
        System.out.println(Thread.currentThread().getName() + " " + 4);
    }

What I would like to see is 2 or 3 of each of these threads running at the same time, but I only see each thread being run once every 3 seconds

I think that you mix things : TaskExecutor/Executor configuration and the frequency rate of the tasks executed by the scheduler.

This configuration means that the task will be executed every 3 seconds :

@Scheduled(fixedRate = 3000, ...)

Adding that : @Async("threadBarExecutor") just means that the Scheduler will use a specific Executor to run the tasks.

It doesn't mean that it will be executed as much as the thread pool size is not full in the configured Executor .
So yes it looks normal that these two tasks be triggered every 3 seconds.

If you want to run these tasks a specific number of times in parallel and every 3 seconds, @Scheduled is not enough.
You should make the scheduler method to invoke another @Asynch method. This can be defined in the same bean or in another, you don't matter.

@Async("threadFooExecutor")
@Scheduled(fixedRate = 3000, initialDelay = 5000)
public void printRepeat3Times() {
    for (int i=0; i<3; i++){
         print();
    }
}


@Async("threadFooExecutor")
public void print() {
     // ...
}

Note that as these methods are annotated with @Asynch , print() invocations don't "block" the current thread and so these could be executed in parallel thanks to the ExecutorService under the hoods.

Update: ok so based on your comments you need the following:

public class ServiceOne {
    @Async
    public void bgTask() {
        System.out.println(Thread.currentThread().getName());
    }
}

public class ServiceTwo {
    @Autowired
    ServiceOne serviceOne;

    @Scheduled(fixedRate = 3000, initialDelay = 5000)
    public void scheduledRunner() {
        int i = 3;
        while (i-- >0 ) {
            serviceOne.bgTask();
        }
    }
}

This way the scheduled method will be executed every three seconds and it will spawn three parallel background tasks. The inject thingie is for the AOP to work with the default weaver which would ignore one of the annotations if methods are in the same class.

According to docs this is what's probably happening:

By default, will be searching for an associated scheduler definition: either a unique TaskScheduler bean in the context, or a TaskScheduler bean named "taskScheduler" otherwise; the same lookup will also be performed for a ScheduledExecutorService bean. If neither of the two is resolvable, a local single-threaded default scheduler will be created and used within the registrar.

I think configuring a ScheduledTaskRegistrar might help:

public class SchedulerConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(4); // Number of simultaneously running @Scheduled functions
        taskScheduler.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM