为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

白猪掌柜的 2023-02-23 10:52:09
要求我需要能够通过 POST 调用触发(长时间运行的)作业并立即返回。一次只有一个线程可以运行作业。这项工作是一项昂贵的工作,如果一项工作已经在进行中,我希望这项工作的所有未来触发器都不做任何事情。代码@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 调用的结果创建的新线程跳过同步方法并在获取锁失败时立即返回)?
查看完整描述

2 回答

?
叮当猫咪

TA贡献1776条经验 获得超12个赞

同步不是完成这项工作的正确工具。你可以这样做:


@RestController

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

    }

}


查看完整回答
反对 回复 2023-02-23
?
交互式爱情

TA贡献1712条经验 获得超3个赞

对于要求 1,如果你只想使用@Async,你应该在服务方法而不是控制器方法上使用它。但请注意,通过使其异步,您将失去对作业的控制,并且无法进行故障处理,除非您通过实现接口来实现@Async和Future处理故障AsyncUncaughtExceptionHandler。


对于要求 3,您可以在服务中有一个 volatile 布尔字段,它在开始作业流程之前设置,并在作业流程完成后取消设置。在您的控制器方法中,您可以检查服务的易失性布尔字段以确定作业是否正在执行,如果作业正在进行则返回适当的消息。另外,确保在处理AsyncUncaughtExceptionHandler接口实现失败时取消设置布尔字段。


服务:


@Service

public class SomeService {


    public volatile boolean isJobInProgress = false;


    @Async

    public Future<String> executeJob() {

        isJobInProgress = true;

        //Job processing logic

        isJobInProgress = false;

    }

}

控制器:


@RestController

public class SomeTask {


    @Autowired

    private SomeService someService;


    @RequestMapping(method = RequestMethod.POST, path = "/triggerJob")

    public void triggerJob() {

        if (!someService.isJobInProgress){

            someService.executeJob(); //can have this in a sync block to be on the safer side. 

        } else {

            return;

        }

    }


}

AsyncUncaughtExceptionHandler 的实现:


public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {


    @Autowired

    private SomeService someService;


    @Override

    public void handleUncaughtException(

            Throwable throwable, Method method, Object... obj) {


        //Handle failure

        if (someService.isJobInProgress){

            someService.isJobInProgress = false;

        }

    }

}

@异步配置:


@Configuration

@EnableAsync

public class SpringAsyncConfig implements AsyncConfigurer {


    @Override

    public Executor getAsyncExecutor() {

        return new ThreadPoolTaskExecutor();

    }


    @Override

    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

        return new CustomAsyncExceptionHandler();

    }


}


查看完整回答
反对 回复 2023-02-23
  • 2 回答
  • 0 关注
  • 102 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信