首页 > 解决方案 > Spring控制器如何每次只服务一个请求,并丢弃同一方法收到的其他请求,直到第一个请求完成

问题描述

因此,正如标题所描述的,我想实现以下目标

@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 个请求执行。同步块内的代码执行可持续约 1 小时。同时,我希望取消到达该方法的每个其他请求。有没有办法做到这一点?

只是为了澄清:

就像现在一样,第一个请求将被处理,当它完成时,等待锁的下一个请求将被处理,然后是下一个正在等待的请求。

我想要的是不允许在第一个请求完成后已经等待服务的其他请求。如果请求是在执行第一个请求期间出现的,我想向用户返回错误请求或其他内容并取消他们的请求。

标签: javaspringmultithreadingsynchronization

解决方案


方法一:

使用单个许可信号量

这是一个示例代码:

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..");
        }
    }
}

司机:

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

(其中之一 输出

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..

推荐阅读