两个线程访问的同步块

时间:2018-03-18 07:45:52

标签: java synchronization

我有一个从控制器方法调用的同步方法。 当两个请求访问时,只有一个应该通过,其他应该被阻止,直到第一个完成。

但是当传入的请求很快时,这实际上是将同一个accountId返回给两个不同的请求,这不是预期的。

请帮助我了解如何同步此getNextAccount()调用,以便它只将一个帐户返回到一个请求。

AccService.java中的方法

private final Object lockObject = new Object();
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Long getNextAccount(String hostport) {
    synchronized (lockObject) {

        Long acc = null;
        try {
            AccountFetch dtls = getAccount();
            if (dtls != null) {
                acc = dtls.getAccId();

                //Set IN_PROGRESS 
                dtls.setStatus("Progress");
                dtls.saveAndFlush(dtls);
                return acc;
            } else {
                log.info("No More Accounts to Process");
            }
        } catch (Exception e) {

            e.getStackTrace();
        }
        return acc;
    }
}

@Autowired
private AccService accSevice;
@GET
@Path("/accprocess")
@Produces(MediaType.APPLICATION_JSON)
public AccountFetch getAccId(@QueryParam("currentHost") final String currentHost,
        @QueryParam("currentPort") final String currentPort) {
    AccountFetch dtls = new AccountFetch();
    try {
        Long batchId = accSevice. getNextAccount(currentHost+"#"+currentPort);
        if (accId != null) {
            dtls.setAccId(String.valueOf(accId));
        } else {
            dtls.setAccId(BLANK_STRING);
        }
    } catch (Exception e) {
        log.error("Exception while getting accId : " + e.getMessage());
    }
    return dtls;
}

public AccountFetch getAccount(){...}

1 个答案:

答案 0 :(得分:1)

如果线程在同一主机上,并且它们使用相同的锁定对象锁定,则synchronized块仅允许您互斥。

根据您最初在问题中所写的内容,似乎不满足这些先决条件中的一个或两个。如果(现在发现)只有一个主机处理这些请求,那么我们必须考虑另一种可能性;即有AccService个对象处理请求的多个实例。

同步也可能有效,问题出在其他地方。例如,getAccount()可能会在后续调用中返回相同的帐户。

基本上,您的代码库中有太多部分我们无法看到。这意味着我们只能理解造成问题的原因。如果每件事都做得恰到好处;即

  • 只有一个主机,
  • 所有线程都共享同一个锁对象,
  • getAccount()已正确实施,
  • 没有其他任何内容更新getAccount在没有正确同步的情况下使用的帐户状态

然后您向我们展示的代码工作。

如果您需要更多帮助,可能需要MCVE。