Как запустить несколько потоков одного и того же процесса в Java - Spring Boot - PullRequest
2 голосов
/ 21 июня 2019

У меня есть запланированное задание, которое должно запускать несколько потоков одного и того же процесса при выполнении. Можно ли задать определенное количество потоков, которое будет запускаться при запуске процесса?

В приложениикласс У меня есть следующие настроенные TaskExecutor bean-компоненты

    @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("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);
    }

Я хотел бы видеть, что 2 или 3 из каждого из этих потоков работаютв то же время, но я вижу, что каждый поток запускается один раз каждые 3 секунды

Ответы [ 2 ]

1 голос
/ 21 июня 2019

Я думаю, что вы смешиваете вещи: TaskExecutor/Executor конфигурация и кратность задач, выполняемых планировщиком.

Эта конфигурация означает, что задача будет выполняться каждые 3 секунды:

@Scheduled(fixedRate = 3000, ...)

Добавление: @Async("threadBarExecutor") просто означает, что планировщик будет использовать определенный Executor для запуска задач,

Это не означает, что оно будет выполнено столько, сколько не будет заполнен размер пула потоков в сконфигурированном Executor.
Так что да, выглядит нормально, что эти две задачи запускаются каждые 3 секунды,

Если вы хотите запускать эти задачи определенное количество раз параллельно и каждые 3 секунды, @Scheduled недостаточно.
Вы должны сделать метод планировщика для вызова другого @Asynch метода.Это может быть определено в одном и том же компоненте или в другом, не имеет значения.

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


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

Обратите внимание, что, поскольку эти методы аннотированы с @Asynch, print() вызовы не «блокируют» текущий поток, и поэтому они могут выполняться параллельно благодаря ExecutorService подкапюшоны.

0 голосов
/ 21 июня 2019

Обновление: хорошо, поэтому, основываясь на ваших комментариях, вам нужно следующее:

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

Таким образом, запланированный метод будет выполняться каждые три секунды, и он будет вызывать три параллельные фоновые задачи. Inject thingie для AOP работает с ткачом по умолчанию, который игнорирует одну из аннотаций, если методы находятся в одном классе.

Согласно документам это, вероятно, происходит:

По умолчанию будет выполняться поиск связанного определения планировщика: либо уникальный компонент TaskScheduler в контексте, либо компонент TaskScheduler с именем "taskScheduler" в противном случае; такой же поиск будет также выполнен для bean-компонента ScheduledExecutorService. Если ни один из них не разрешаем, будет создан локальный однопоточный планировщик по умолчанию , который будет использоваться в регистраторе.

Я думаю, что настройка ScheduledTaskRegistrar может помочь:

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);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...