Java:如果另一个线程已经在其中,则新线程将跳过同步方法

要求

  1. 我需要能够通过 POST 调用触发(长时间运行的)作业并立即返回。

  2. 一次只有一个线程可以运行作业。

  3. 这项工作是一项昂贵的工作,如果一项工作已经在进行中,我希望这项工作的所有未来触发器都不做任何事情。

代码

@RestControllerpublic class SomeTask {    private SomeService someService;    @Autowired
    public SomeTask(SomeService someService) {        this.someService = someService;
    }    @Async // requirement 1
    @RequestMapping(method = RequestMethod.POST, path = "/triggerJob")
    public void triggerJob() {
        expensiveLongRunningJob();
    }    /**
     * Synchronized in order to restrict multiple invocations. // requirement 2
     *
     */
    private synchronized void expensiveLongRunningJob() { 
        someService.executedJob();
    }
}

问题

上面的代码要求 1 和 2 得到满足。满足要求 3 的最佳方法是什么(作为 POST 调用的结果创建的新线程跳过同步方法并在获取锁失败时立即返回)?


白猪掌柜的
浏览 103回答 2
2回答

叮当猫咪

同步不是完成这项工作的正确工具。你可以这样做:@RestControllerpublic class SomeTask {    private SomeService someService;    private final AtomicBoolean isTriggered = new AtomicBoolean();    @Autowired    public SomeTask(SomeService someService) {        this.someService = someService;    }    @Async // requirement 1    @RequestMapping(method = RequestMethod.POST, path = "/triggerJob")    public void triggerJob() {        if (!isTriggered.getAndSet(true)) {            try {                expensiveLongRunningJob();            } finally {                isTriggered.set(false);            }        }    }    /**     * only runs once at a time, in the thread that sets isTriggered to true     */    private void expensiveLongRunningJob() {         someService.executedJob();    }}

交互式爱情

对于要求 1,如果你只想使用@Async,你应该在服务方法而不是控制器方法上使用它。但请注意,通过使其异步,您将失去对作业的控制,并且无法进行故障处理,除非您通过实现接口来实现@Async和Future处理故障AsyncUncaughtExceptionHandler。对于要求 3,您可以在服务中有一个 volatile 布尔字段,它在开始作业流程之前设置,并在作业流程完成后取消设置。在您的控制器方法中,您可以检查服务的易失性布尔字段以确定作业是否正在执行,如果作业正在进行则返回适当的消息。另外,确保在处理AsyncUncaughtExceptionHandler接口实现失败时取消设置布尔字段。服务:@Servicepublic class SomeService {&nbsp; &nbsp; public volatile boolean isJobInProgress = false;&nbsp; &nbsp; @Async&nbsp; &nbsp; public Future<String> executeJob() {&nbsp; &nbsp; &nbsp; &nbsp; isJobInProgress = true;&nbsp; &nbsp; &nbsp; &nbsp; //Job processing logic&nbsp; &nbsp; &nbsp; &nbsp; isJobInProgress = false;&nbsp; &nbsp; }}控制器:@RestControllerpublic class SomeTask {&nbsp; &nbsp; @Autowired&nbsp; &nbsp; private SomeService someService;&nbsp; &nbsp; @RequestMapping(method = RequestMethod.POST, path = "/triggerJob")&nbsp; &nbsp; public void triggerJob() {&nbsp; &nbsp; &nbsp; &nbsp; if (!someService.isJobInProgress){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; someService.executeJob(); //can have this in a sync block to be on the safer side.&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}AsyncUncaughtExceptionHandler 的实现:public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {&nbsp; &nbsp; @Autowired&nbsp; &nbsp; private SomeService someService;&nbsp; &nbsp; @Override&nbsp; &nbsp; public void handleUncaughtException(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Throwable throwable, Method method, Object... obj) {&nbsp; &nbsp; &nbsp; &nbsp; //Handle failure&nbsp; &nbsp; &nbsp; &nbsp; if (someService.isJobInProgress){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; someService.isJobInProgress = false;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}@异步配置:@Configuration@EnableAsyncpublic class SpringAsyncConfig implements AsyncConfigurer {&nbsp; &nbsp; @Override&nbsp; &nbsp; public Executor getAsyncExecutor() {&nbsp; &nbsp; &nbsp; &nbsp; return new ThreadPoolTaskExecutor();&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {&nbsp; &nbsp; &nbsp; &nbsp; return new CustomAsyncExceptionHandler();&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java