Spring 控制器如何每次只服务 1 个请求,并在第一个请求完成之前丢弃使用相同方法收到的其他请求
Spring controller how to serve only 1 request each time, and discard other requests received for the same method until first request has finished
正如标题所描述的,我想实现以下目标
@Controller
public class ImportController {
@RequestMapping(value = "/{File}", method = RequestMethod.GET)
@LogAware
public String import(@PathVariable(value = "File") String excel, Model model) {
try {
synchronized (this) {
//code...
}
}
}
}
我希望代码一次只针对 1 个请求执行。 synchronized 块内代码的执行可以持续大约 1 小时。与此同时,我希望取消到达该方法的彼此请求。有什么办法可以实现吗?
澄清一下:
因为现在第一个请求将被服务,当它完成时,下一个正在等待锁定的请求将被服务,然后是下一个正在等待的请求。
我想要的是在第一个请求完成后不允许其他已经在等待服务的请求。如果请求是在第一个请求执行期间发出的,我想 return 向用户发送错误请求或其他内容并取消他们的请求。
这是一种你可以考虑的方法。这在 AtomicBoolean 中使用全局状态,希望在您的用例中使用它是安全的(?)!
看到这个 When do I need to use AtomicBoolean in Java?
static AtomicBoolean atomicBoolean = new AtomicBoolean(false);
//controller definition
if(atomicBoolean.compareAndSet(false, true)) {
// your logic
atomicBoolean.compareAndSet(true, false);
}
// rest of the controller logic
但是,请考虑将请求排队并将其作为后台任务处理的选项。在大多数情况下,不建议长时间保持套接字和 HTTP 打开。
方法一:
使用单证Semaphore
这是一个示例代码:
import java.util.concurrent.Semaphore;
public class Test {
Semaphore s = new Semaphore(1); // Single permit.
public void nonBlockingMethod() throws InterruptedException {
// A thread tries to acquire a permit, returns immediately if cannot
if (s.tryAcquire()) {
// No. of permits = 0
try {
System.out.println(Thread.currentThread().getName() + " begins execution..");
// long running task
Thread.sleep(4000);
System.out.println(Thread.currentThread().getName() + " exiting..");
} finally {
s.release(); // Release permit. No. of permits = 1
}
} else {
System.out.println(Thread.currentThread().getName() + " cannot run as another thread is already running..");
}
}
}
方法二:
示例代码:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test {
Lock s = new ReentrantLock();
public void nonBlockingMethod() throws InterruptedException {
if (s.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + " begins execution..");
// long running task
Thread.sleep(4000);
System.out.println(Thread.currentThread().getName() + " exiting..");
} finally {
s.unlock();
}
} else {
System.out.println(Thread.currentThread().getName() + " cannot run as another thread is already running..");
}
}
}
Driver:
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
Runnable r = () -> {
try {
t.nonBlockingMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
for (int i = 0; i < 3; i++) {
new Thread(r, "Loop-1-Thread-" + i).start();
}
Thread.sleep(3999);
// one of the threads in this iteration may get to run the task
for (int i = 3; i < 8; i++) {
new Thread(r, "Loop-2-Thread-" + i).start();
}
}
(其中之一) 输出 (s):
Loop-1-Thread-2 cannot run as another thread is already running..
Loop-1-Thread-1 cannot run as another thread is already running..
Loop-1-Thread-0 begins execution..
Loop-2-Thread-3 cannot run as another thread is already running..
Loop-2-Thread-4 cannot run as another thread is already running..
Loop-2-Thread-5 cannot run as another thread is already running..
Loop-1-Thread-0 exiting..
Loop-2-Thread-6 begins execution..
Loop-2-Thread-7 cannot run as another thread is already running..
Loop-2-Thread-6 exiting..
正如标题所描述的,我想实现以下目标
@Controller
public class ImportController {
@RequestMapping(value = "/{File}", method = RequestMethod.GET)
@LogAware
public String import(@PathVariable(value = "File") String excel, Model model) {
try {
synchronized (this) {
//code...
}
}
}
}
我希望代码一次只针对 1 个请求执行。 synchronized 块内代码的执行可以持续大约 1 小时。与此同时,我希望取消到达该方法的彼此请求。有什么办法可以实现吗?
澄清一下:
因为现在第一个请求将被服务,当它完成时,下一个正在等待锁定的请求将被服务,然后是下一个正在等待的请求。
我想要的是在第一个请求完成后不允许其他已经在等待服务的请求。如果请求是在第一个请求执行期间发出的,我想 return 向用户发送错误请求或其他内容并取消他们的请求。
这是一种你可以考虑的方法。这在 AtomicBoolean 中使用全局状态,希望在您的用例中使用它是安全的(?)!
看到这个 When do I need to use AtomicBoolean in Java?
static AtomicBoolean atomicBoolean = new AtomicBoolean(false);
//controller definition
if(atomicBoolean.compareAndSet(false, true)) {
// your logic
atomicBoolean.compareAndSet(true, false);
}
// rest of the controller logic
但是,请考虑将请求排队并将其作为后台任务处理的选项。在大多数情况下,不建议长时间保持套接字和 HTTP 打开。
方法一:
使用单证Semaphore
这是一个示例代码:
import java.util.concurrent.Semaphore;
public class Test {
Semaphore s = new Semaphore(1); // Single permit.
public void nonBlockingMethod() throws InterruptedException {
// A thread tries to acquire a permit, returns immediately if cannot
if (s.tryAcquire()) {
// No. of permits = 0
try {
System.out.println(Thread.currentThread().getName() + " begins execution..");
// long running task
Thread.sleep(4000);
System.out.println(Thread.currentThread().getName() + " exiting..");
} finally {
s.release(); // Release permit. No. of permits = 1
}
} else {
System.out.println(Thread.currentThread().getName() + " cannot run as another thread is already running..");
}
}
}
方法二:
示例代码:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test {
Lock s = new ReentrantLock();
public void nonBlockingMethod() throws InterruptedException {
if (s.tryLock()) {
try {
System.out.println(Thread.currentThread().getName() + " begins execution..");
// long running task
Thread.sleep(4000);
System.out.println(Thread.currentThread().getName() + " exiting..");
} finally {
s.unlock();
}
} else {
System.out.println(Thread.currentThread().getName() + " cannot run as another thread is already running..");
}
}
}
Driver:
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
Runnable r = () -> {
try {
t.nonBlockingMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
for (int i = 0; i < 3; i++) {
new Thread(r, "Loop-1-Thread-" + i).start();
}
Thread.sleep(3999);
// one of the threads in this iteration may get to run the task
for (int i = 3; i < 8; i++) {
new Thread(r, "Loop-2-Thread-" + i).start();
}
}
(其中之一) 输出 (s):
Loop-1-Thread-2 cannot run as another thread is already running..
Loop-1-Thread-1 cannot run as another thread is already running..
Loop-1-Thread-0 begins execution..
Loop-2-Thread-3 cannot run as another thread is already running..
Loop-2-Thread-4 cannot run as another thread is already running..
Loop-2-Thread-5 cannot run as another thread is already running..
Loop-1-Thread-0 exiting..
Loop-2-Thread-6 begins execution..
Loop-2-Thread-7 cannot run as another thread is already running..
Loop-2-Thread-6 exiting..