4

我有这门课

@Service
@Profile("async")
public class MyServiceImplAsync implements MyService {
..

    @Async
    @Override
    public void printGreetings(String name) {
        //do something and sleep 10 seconds
    }

    @Async
    @Override
    public Future<String> doSomething(String text) {
        //do something and sleep 25 seconds
        return new AsyncResult<String>(text);
    }

}

观察,这两种方法使用@Async

现在,我也有以下内容:

@Component
public class MySchedule {
..
    @Scheduled(cron="*/5 * * * * ?")
    public void schedule(){
        logger.info("Schedule working at {}", simpleDateFormat.format( new Date() ));
        this.myService.printGreetings("Manolito");
    }

    @Scheduled(cron="*/30 * * * * ?")
    public void scheduleFuture(){
        logger.info("Schedule Future working at {}", simpleDateFormat.format( new Date() ));

        try {
            logger.info("{}", this.myService.doSomething("manolito").get(26, TimeUnit.SECONDS));
        } 
        catch (InterruptedException | ExecutionException | TimeoutException e) {
            logger.error("Error: {}, Class: {}", e.getMessage(), e.getClass());
        }
    }

}

schedule()方法必须每 5 秒执行一次,该scheduleFuture()方法必须每 30 秒执行一次。

我对以下情况感到困惑:

我可以看到该schedule()方法每 5 秒安静地工作,然后当scheduleFuture()开始运行时,scheduleFuture()由于 Future 的get方法,该方法仍然被阻塞。我对此很好,因为这是Future API的预期行为。

我想:

只有scheduleFuture()方法应该被阻止。

问题:我不明白为什么也scheduleFuture()阻止其他schedule()方法!我的意思是如果scheduleFuture()被封锁,schedule()遗体也被封锁!它不能开始一个新的循环或执行。直到scheduleFuture()再次解锁。

为什么会这样?

我有两种 @Scheduled方法,每一种都调用两个用bean注释的不同方法(如果类是相同的情况@AsyncMyServiceImplAsync@Scope("prototype")

提前致谢。

4

1 回答 1

5

因为您正在阻塞用于安排这些任务的单个线程。来自@EnableScheduling

在上述所有场景中,都使用了默认的单线程任务执行器。当需要更多控制时,@Configuration 类可以实现 SchedulingConfigurer。这允许访问底层的 ScheduledTaskRegistrar 实例。

@Configuration
@EnableScheduling
public class AppConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod="shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(100);
    }
}

当您遇到此类问题时,一个好主意是配置您的日志框架以显示线程的名称。使用 log4j,您需要添加%t到您的PatternLayout

于 2014-08-08T08:02:21.930 回答