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

问题描述

要求

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

  2. 一次只能有一个线程运行该作业。

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

代码

@RestController
public 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 调用的结果创建的新线程,跳过同步方法并在获取锁失败时立即返回)?

标签: javaspringmultithreading

解决方案


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

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

推荐阅读