我有一个从 Controller 方法调用的同步方法。 当两个请求访问时,只有一个应该通过,其他的应该被阻止,直到第一个请求完成。
但是当传入请求很快时,这实际上是向两个不同的请求返回相同的 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(){...}
最佳答案
只有当线程位于同一主机上并且使用相同的锁对象进行锁定时,synchronized
block 才会提供互斥。
根据您最初在问题中所写的内容,似乎不满足这些先决条件之一或两个。如果(正如现在所发生的那样)只有一台主机处理这些请求,那么我们必须考虑另一种可能性;即有多个 AccService
对象实例处理请求。
也有可能同步正在工作,但问题出在其他地方。例如,getAccount()
可能会在连续调用时返回相同的帐户。
基本上,您的代码库中有太多我们看不到的部分。这意味着我们只能对导致问题的原因进行理论分析。如果每件事都做对了;即
- 只有一台主机,
- 所有线程共享同一个锁对象,
getAccount()
已正确实现,并且- 如果没有正确的同步,则不会更新
getAccount
使用的帐户状态,
那么您向我们展示的代码将会工作。
如果您需要更多帮助,可能需要 MCVE。
关于java - 两个线程访问的同步块(synchronized block),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49345622/