我知道字符串文字指向同一个对象,并且对相同的值具有相同的引用。所以它非常适合我的同步情况。我测试了下面的代码,它正是我想要的。我想在相同的字符串上有锁,而在字符串不同时没有锁。
public class SampleThread extends Thread {
String lock;
public SampleThread(String s) {
this.lock = s;
}
@Override
public void run() {
long id = this.getId();
synchronized (lock) {
for (int i = 0; i < 1000; i++) {
System.out.println("thread with id: "+id);
}
}
}
public static void main(String[] args) {
SampleThread s1 = new SampleThread("mina");
SampleThread s2 = new SampleThread("mina");
s1.start();
s2.start();
}
}
第一个线程完成,然后第二个线程启动。我将相同的代码放入 Controller 中,这对于相同的文字不起作用。两个请求进入 block 而不考虑字符串锁。有没有什么办法解决这一问题?这是我测试过的示例,但不起作用。
@RequestMapping("/test/{name}")
public void test(@PathVariable("name") String test) throws InterruptedException {
String a = test;
synchronized (String.valueOf(a)) {
System.out.println("first");
TimeUnit.SECONDS.sleep(4);
System.out.println("finish");
}
}
最佳答案
编译器将优化相同值的字符串,并使它们成为代码的一部分时完全相同的实例,如下所示:
if ("abc" == "abc")
但是,如果字符串是在运行时创建的,就像您的情况一样,其中字符串测试是从 URL 解析的,那么它不会以相同的方式进行优化,并且它是它自己的实例。
所以http://localhost/test/name1执行两次将创建两个单独的字符串实例,它们不会比较 ==,这意味着对其进行同步不会给出您期望的结果。
您似乎正在尝试同步处理相同的“测试”值,但允许异步处理不同的测试值。如果是这种情况,那么您可以执行一些操作,例如保留正在处理的值的映射,其中“测试”值是键,并且将 Object 的实例存储为用作互斥锁的值。查找后然后在互斥锁上进行同步。
关于java - 具有相同值的字符串文字不会在 Controller 中保留同步锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58573141/