第一次写技术文档,因为担心很多以前做过的东西,又要接着做一遍。所以开始写一些东西记录一下。
问题:如果写一个接口,其他人调用这个结果的时候,根据接口的参数来加锁。
环境:因为没有写demo 的习惯,所以都是直接在真实项目里面做的示例。
后台:Spring boot 写的接口
前台:vue 写的网络请求
话不多说:上代码
@GetMapping(value = "/he/{username}")
public String setexcle2(@PathVariable String username) {
StringBuffer sb=new StringBuffer();
sb.append(username);
synchronized(sb.toString().intern()) {
System.out.println(username);
try {
//延时3秒执行
Thread.currentThread().sleep(3000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
String username2 = username + "运算结果:::::: ";
System.out.println(username2);
}
return "你好!世界" + username;
}
这个就是一个get请求的接口:接口地址是 本机ip:8080/main/he,当然这个不重要。重要的是里面的方法。
这就是关键。
原因是
再看String
JVM内存区域里面有一块常量池,关于常量池的分配:
JDK6的版本,常量池在持久代PermGen中分配
JDK7的版本,常量池在堆Heap中分配
字符串是存储在常量池中的,有两种类型的字符串数据会存储在常量池中:
1.编译期就可以确定的字符串,即使用""引起来的字符串,比如String a = "123"、String b = "1" + B.getStringDataFromDB() + "2" + C.getStringDataFromDB()、这里的"123"、"1"、"2"都是编译期间就可以确定的字符串,因此会放入常量池,而B.getStringDataFromDB()、C.getStringDataFromDB()这两个数据由于编译期间无法确定,因此它们是在堆上进行分配的
2.使用String的intern()方法操作的字符串,比如String b = B.getStringDataFromDB().intern(),尽管B.getStringDataFromDB()方法拿到的字符串是在堆上分配的,但是由于后面加入了intern(),因此B.getStringDataFromDB()方法的结果,会写入常量池中
3.常量池中的String数据有一个特点:每次取数据的时候,如果常量池中有,直接拿常量池中的数据;如果常量池中没有,将数据写入常量池中并返回常量池中的数据。
因此回到我们之前的场景,使用StringBuilder拼接字符串每次返回一个new的对象,但是使用intern()方法则不一样:
接下来就是测试了:
在vue里面进行测试,我们循环5次,每次里面放2个请求,一个相同,一个不同。看看执行的结果。
posthttp(){
let that = this;
for(var i=0;i<5;i++){
that.$http({
url: "http://localhost:8090/main/he/哇哈哈"+(i),
method: 'get',
}).then((res) => {
console.log(res);
}).catch((res) => {
console.log('SideSec.vue :', res);
});
that.$http({
url: "http://localhost:8090/main/he/测试",
method: 'get',
}).then((res) => {
console.log(res);
}).catch((res) => {
console.log('SideSec.vue :', res);
});
}
最后我们执行这个vue程序 。
npm run dev
最后我们看看控制台的打印
可以看出 请求参数为测试的 都是加了锁 同步的。哇哈哈1 哇哈哈2 就是没有同步的。
忽然感觉写的很烂,准备把名字改了。
这样我们就能看出这里李四是同步了的。