如果 2+ 个前端执行相同的请求,我怎样才能使后端只允许第一个请求而忽略其余的请求?
If 2+ front-ends execute the same request, how can I make it so the back-end only allows the first request and ignores the rest?
我想做什么?
当 2+ 个前端通过 socket 发出请求时,我只希望后端处理其中 1 个请求并拒绝其他请求。
目前尝试这样做的代码是什么?
后端代码。
// Original code.
public IoMessage create(IoMessage request) {
Adventure[] adventures = null;
AdventureIoMessage createRequest = null;
StringBuilder message = new StringBuilder();
// Thinking of putting some "locking" code around this if statement?
// Something like "If this function is already in process, deny other requests and remove them"?
if (request instanceof AdventureIoMessage) {
createRequest = (AdventureIoMessage) request;
DatabaseManager databaseManager = Application.getDatabaseManager();
Adventure adventure = Adventure.read(databaseManager);
if (adventure == null || adventure.getStartTime() == 0 || !adventure.isActive()) {
createAdventure(adventures, createRequest, message);
} else {
message.append("New adventure already exists and hasn't ended yet!");
}
} else {
message.append("Request formatting is invalid!");
}
return new AdventureIoMessage(adventures, createRequest, message);
}
// My suggested code 1 using a Boolean.
public IoMessage create(IoMessage request) {
Adventure[] adventures = null;
AdventureIoMessage createRequest = null;
StringBuilder message = new StringBuilder();
Boolean isRequestAlreadyRunning = false;
if (!isRequestAlreadyRunning) {
isRequestAlreadyRunning = true;
if (request instanceof AdventureIoMessage) {
createRequest = (AdventureIoMessage) request;
DatabaseManager databaseManager = Application.getDatabaseManager();
Adventure adventure = Adventure.read(databaseManager);
if (adventure == null || !adventure.isActive()) {
createAdventure(adventures, createRequest, message);
} else {
message.append("New adventure already exists and hasn't ended yet!");
}
} else {
message.append("Request formatting is invalid!");
}
isRequestAlreadyRunning = false; // Done processing.
}
return new AdventureIoMessage(adventures, createRequest, message);
}
// My suggested code 2 using AtomicBoolean and CountDownLatch.
public IoMessage create(IoMessage request) {
Adventure[] adventures = null;
AdventureIoMessage createRequest = null;
StringBuilder message = new StringBuilder();
AtomicBoolean updateStarted = new AtomicBoolean();
CountDownLatch updateFinished = new CountDownLatch(1);
if (updateStarted.compareAndSet(false, true) {
if (request instanceof AdventureIoMessage) {
createRequest = (AdventureIoMessage) request;
DatabaseManager databaseManager = Application.getDatabaseManager();
Adventure adventure = Adventure.read(databaseManager);
if (adventure == null || !adventure.isActive()) {
createAdventure(adventures, createRequest, message);
} else {
message.append("New adventure already exists and hasn't ended yet!");
}
} else {
message.append("Request formatting is invalid!");
}
updateFinished.countDown();
} else {
updateFinished.await();
}
return new AdventureIoMessage(adventures, createRequest, message);
}
对于建议的代码 2,也只尝试了 AtomicBoolean
。
我期望结果是什么?
我考虑过保留某种变量来检查 create()
是否仍会发生,希望只有 1 个请求通过。
实际结果如何?
当 2+ 个前端通过 socket emit 发出请求时,create()
中的 2 个发生,尽管内部有检查逻辑。
我认为可能是什么问题?
一个计时问题,因为 2 个以上的前端可以在没有适当检查的情况下同时访问此 create()
方法。代码的原始逻辑在它们不同时触发的过程中起作用。我希望这是有道理的,因为很难用这个词来形容 Java.
编辑:
我最终确定的工作解决方案:
// Within a class...
AtomicBoolean isRequestAlreadyRunning = new AtomicBoolean();
public IoMessage create(IoMessage request) {
Adventure[] adventures = null;
AdventureIoMessage createRequest = null;
StringBuilder message = new StringBuilder();
if (updateStarted.compareAndSet(false, true) {
try {
if (request instanceof AdventureIoMessage) {
createRequest = (AdventureIoMessage) request;
DatabaseManager databaseManager = Application.getDatabaseManager();
Adventure adventure = Adventure.read(databaseManager);
if (adventure == null || !adventure.isActive()) {
createAdventure(adventures, createRequest, message);
} else {
message.append("New adventure already exists and hasn't ended yet!");
}
} else {
message.append("Request formatting is invalid!");
}
} finally {
isRequestAlreadyRunning.set(false);
}
}
return new AdventureIoMessage(adventures, createRequest, message);
}
问题:在Java中,每个方法都有自己的堆栈,所以在方法内部分配的所有变量都是唯一的。
解决方案:
- 把你的
isRequestAlreadyRunning
作为成员变量,而不是方法变量
- 成为
boolean isRequestAlreadyRunning
,而不是 Boolean isRequestAlreadyRunning
- 使其成为
volatile
,如 private volatile boolean isRequestAlreadyRunning
那么您的第一次尝试应该会奏效。
由于同样的原因,您的第二次尝试将失败。
或者,搜索 Java mutex,如“互斥”,您会发现许多 类 和技术专门用于此, 除了 sychronized(myLockObj)
语句。
我想做什么?
当 2+ 个前端通过 socket 发出请求时,我只希望后端处理其中 1 个请求并拒绝其他请求。
目前尝试这样做的代码是什么?
后端代码。
// Original code.
public IoMessage create(IoMessage request) {
Adventure[] adventures = null;
AdventureIoMessage createRequest = null;
StringBuilder message = new StringBuilder();
// Thinking of putting some "locking" code around this if statement?
// Something like "If this function is already in process, deny other requests and remove them"?
if (request instanceof AdventureIoMessage) {
createRequest = (AdventureIoMessage) request;
DatabaseManager databaseManager = Application.getDatabaseManager();
Adventure adventure = Adventure.read(databaseManager);
if (adventure == null || adventure.getStartTime() == 0 || !adventure.isActive()) {
createAdventure(adventures, createRequest, message);
} else {
message.append("New adventure already exists and hasn't ended yet!");
}
} else {
message.append("Request formatting is invalid!");
}
return new AdventureIoMessage(adventures, createRequest, message);
}
// My suggested code 1 using a Boolean.
public IoMessage create(IoMessage request) {
Adventure[] adventures = null;
AdventureIoMessage createRequest = null;
StringBuilder message = new StringBuilder();
Boolean isRequestAlreadyRunning = false;
if (!isRequestAlreadyRunning) {
isRequestAlreadyRunning = true;
if (request instanceof AdventureIoMessage) {
createRequest = (AdventureIoMessage) request;
DatabaseManager databaseManager = Application.getDatabaseManager();
Adventure adventure = Adventure.read(databaseManager);
if (adventure == null || !adventure.isActive()) {
createAdventure(adventures, createRequest, message);
} else {
message.append("New adventure already exists and hasn't ended yet!");
}
} else {
message.append("Request formatting is invalid!");
}
isRequestAlreadyRunning = false; // Done processing.
}
return new AdventureIoMessage(adventures, createRequest, message);
}
// My suggested code 2 using AtomicBoolean and CountDownLatch.
public IoMessage create(IoMessage request) {
Adventure[] adventures = null;
AdventureIoMessage createRequest = null;
StringBuilder message = new StringBuilder();
AtomicBoolean updateStarted = new AtomicBoolean();
CountDownLatch updateFinished = new CountDownLatch(1);
if (updateStarted.compareAndSet(false, true) {
if (request instanceof AdventureIoMessage) {
createRequest = (AdventureIoMessage) request;
DatabaseManager databaseManager = Application.getDatabaseManager();
Adventure adventure = Adventure.read(databaseManager);
if (adventure == null || !adventure.isActive()) {
createAdventure(adventures, createRequest, message);
} else {
message.append("New adventure already exists and hasn't ended yet!");
}
} else {
message.append("Request formatting is invalid!");
}
updateFinished.countDown();
} else {
updateFinished.await();
}
return new AdventureIoMessage(adventures, createRequest, message);
}
对于建议的代码 2,也只尝试了 AtomicBoolean
。
我期望结果是什么?
我考虑过保留某种变量来检查 create()
是否仍会发生,希望只有 1 个请求通过。
实际结果如何?
当 2+ 个前端通过 socket emit 发出请求时,create()
中的 2 个发生,尽管内部有检查逻辑。
我认为可能是什么问题?
一个计时问题,因为 2 个以上的前端可以在没有适当检查的情况下同时访问此 create()
方法。代码的原始逻辑在它们不同时触发的过程中起作用。我希望这是有道理的,因为很难用这个词来形容 Java.
编辑:
我最终确定的工作解决方案:
// Within a class...
AtomicBoolean isRequestAlreadyRunning = new AtomicBoolean();
public IoMessage create(IoMessage request) {
Adventure[] adventures = null;
AdventureIoMessage createRequest = null;
StringBuilder message = new StringBuilder();
if (updateStarted.compareAndSet(false, true) {
try {
if (request instanceof AdventureIoMessage) {
createRequest = (AdventureIoMessage) request;
DatabaseManager databaseManager = Application.getDatabaseManager();
Adventure adventure = Adventure.read(databaseManager);
if (adventure == null || !adventure.isActive()) {
createAdventure(adventures, createRequest, message);
} else {
message.append("New adventure already exists and hasn't ended yet!");
}
} else {
message.append("Request formatting is invalid!");
}
} finally {
isRequestAlreadyRunning.set(false);
}
}
return new AdventureIoMessage(adventures, createRequest, message);
}
问题:在Java中,每个方法都有自己的堆栈,所以在方法内部分配的所有变量都是唯一的。
解决方案:
- 把你的
isRequestAlreadyRunning
作为成员变量,而不是方法变量 - 成为
boolean isRequestAlreadyRunning
,而不是Boolean isRequestAlreadyRunning
- 使其成为
volatile
,如private volatile boolean isRequestAlreadyRunning
那么您的第一次尝试应该会奏效。
由于同样的原因,您的第二次尝试将失败。
或者,搜索 Java mutex,如“互斥”,您会发现许多 类 和技术专门用于此, 除了 sychronized(myLockObj)
语句。