请教一个 Spring 并发请求的问题(如果有一个耗时操作,首次请求会影响其他并发请求)# Java #SpringBoot

2019-08-20 20:29:23 +08:00
 hiw2016
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequestMapping("/")
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @GetMapping("/hello")
    private String sayHello() throws InterruptedException {
        String id = UUID.randomUUID().toString();
        System.out.println("进入 1: " + id + " 时间: " + System.currentTimeMillis() + " 线程 id: " + Thread.currentThread().getId());
        // 模拟耗时操作
        Thread.sleep(5000);
        System.out.println("进入 2: " + id + " 时间: " + System.currentTimeMillis() + " 线程 id: " + Thread.currentThread().getId());
        return "hello2";
    }
}

进入 1: 26ae2ea9-7e5c-4bd7-bc2d-8c4d0907d18a 时间: 1566302327095 线程 id: 28
进入 2: 26ae2ea9-7e5c-4bd7-bc2d-8c4d0907d18a 时间: 1566302332099 线程 id: 28
进入 1: 82768b68-3a05-4768-8290-8b43a176a57e 时间: 1566302332125 线程 id: 30
进入 1: 05337b19-9a5a-41e9-8c9b-944d8ceeb06c 时间: 1566302332125 线程 id: 29
进入 1: 3b7eea0a-4d8c-4878-9e21-741f1e6d2e76 时间: 1566302332125 线程 id: 32
进入 1: 587305cd-89fc-441d-a575-ab436a63ad40 时间: 1566302332125 线程 id: 31
进入 2: 3b7eea0a-4d8c-4878-9e21-741f1e6d2e76 时间: 1566302337127 线程 id: 32
进入 2: 05337b19-9a5a-41e9-8c9b-944d8ceeb06c 时间: 1566302337127 线程 id: 29
进入 2: 587305cd-89fc-441d-a575-ab436a63ad40 时间: 1566302337127 线程 id: 31
进入 2: 82768b68-3a05-4768-8290-8b43a176a57e 时间: 1566302337127 线程 id: 30
进入 1
进入 1
进入 1
进入 1
进入 1
进入 2
进入 2
进入 2
进入 2
进入 2
2764 次点击
所在节点    问与答
21 条回复
hiw2016
2019-08-20 21:00:04 +08:00
我应该换到 Java 节点么 🙈
hiw2016
2019-08-20 21:00:44 +08:00
@hiw2016 超时了,换不了了
HuasLeung
2019-08-20 21:28:37 +08:00
spring 中的 controller 是非线程安全的,多个线程访问会导致意料不到的结果
hiw2016
2019-08-20 21:33:44 +08:00
@HuasLeung 感谢你的回复~ 我重复尝试过多次,总是第一次的请求完整处理完,才开始处理后续请求,而后续请求是可以多线程进入方法并打印出「进入 1 」。疑问在于为什么第一次不能多线程执行方法呢?
HuasLeung
2019-08-20 21:44:07 +08:00
@hiw2016
````
// 模拟耗时操作
Thread.sleep(5000);
````
sleep()方法是不会释放锁的。在设置的 5 秒钟内不清楚你的请求的时间间隔是怎么样的,只要你的第 2 次请求在 5 秒后请求都能得到“总是第一次的请求完整处理完”
HuasLeung
2019-08-20 21:44:57 +08:00
@HuasLeung 打错,5 秒钟内
limuyan44
2019-08-20 21:56:29 +08:00
不应该出现这种情况的,把 UUID.randomUUID()去掉试看看呢。
HuasLeung
2019-08-20 22:09:27 +08:00
````
public class DemoApplication {
volatile String id = UUID.randomUUID().toString();


}
````
HuasLeung
2019-08-20 22:12:24 +08:00
@HuasLeung
````
public class DemoApplication {
private volatile String id = UUID.randomUUID().toString();
//省略
@GetMapping("/hello")
private String sayHello() throws InterruptedException {
System.out.println("进入 1: " + this.id + " 时间: " + System.currentTimeMillis() + " 线程 id: " + Thread.currentThread().getId());
// 模拟耗时操作
Thread.sleep(5000);
System.out.println("进入 2: " + this.id + " 时间: " + System.currentTimeMillis() + " 线程 id: " + Thread.currentThread().getId());
return "hello2";
}

}
````
手机写代码真是一点不方便,没编辑完就发出去了……试试看,这样写应该能解决单例模式的线程不安全问题
gIrl1990
2019-08-20 22:12:29 +08:00
ab 是啥工具
iffi
2019-08-20 22:25:10 +08:00
没明白你想问什么
Farigen
2019-08-20 22:25:26 +08:00
@gIrl1990 ab 是 Apache 的网站压力测试工具
notreami
2019-08-20 22:31:01 +08:00
问题的关键是,你以为设置 500ms 休眠就真的精准 500ms ???
notreami
2019-08-20 22:36:16 +08:00
额,不对。看错了。你这是认为,为啥第一次请求结束了才有第二次请求。
anzu
2019-08-20 22:46:29 +08:00
为什么会有这种预期?如果一直每秒都有一个请求进来,那不是永远都无法进入 2 阶段了?
hiw2016
2019-08-21 07:32:29 +08:00
@HuasLeung 感谢,我换了一种测试方式,手动在五个不同的终端中 curl,输出是我的预期了。那可能是我理解错了 ab 的机制。
hiw2016
2019-08-21 07:33:02 +08:00
@limuyan44 也是一样的,但是我换了一种测试方法,手动在五个不同的终端中 curl,输出是我的预期了。可能是我理解错了 ab 的机制。
hiw2016
2019-08-21 07:33:42 +08:00
@notreami 对的,但是换成手动在五个不同的终端中 curl,输出是我的预期了。可能是我理解错了 ab 的机制。
hiw2016
2019-08-21 07:34:41 +08:00
@anzu 因为 Spring 每一个请求是一个单独的线程,所以会每个单独的处理。
notreami
2019-08-21 10:33:20 +08:00
这跟 spring boot 没啥关系,ab 测试会先请求一次,并将返回值当作基准数据,比如 Document Length 参数。然后才会马力全开的测试。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/593628

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX