具有相同值的字符串文字不会在控制器中保持同步锁

问题描述 投票:1回答:2

我知道String文字指向相同的对象,并且对相同的值具有相同的引用。所以这正是我的同步案例。我测试了下面的代码,它正是我想要的。我想对相同的字符串加锁,并且当字符串不同时不加锁。

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

第一个线程完成,然后第二个线程启动。我在控制器中放置了相同的代码,这对于相同的文字不起作用。两个请求进入该块而不考虑字符串锁定。有没有什么办法解决这一问题?这是我测试过的示例,不起作用。

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

}
java string spring-boot controller synchronized
2个回答
1
投票

编译器将优化具有相同值的字符串,并使它们成为代码的一部分时使其完全相同,例如:

if ("abc" == "abc")

但是,如果像在您的情况下那样在运行时创建字符串,则从URL解析String测试,那么它不会以相同的方式进行优化,而是它自己的实例。

因此,执行两次的http://localhost/test/name1将创建两个单独的字符串实例,这些实例将不比较==,这意味着对其进行同步将无法提供您期望的结果。

似乎您正在尝试使相同的“测试”值的处理保持同步,但允许不同的测试值进行异步处理。如果是这种情况,那么您可以做一些事情,例如保留正在处理的值的映射,其中“测试”值是键,并且将Object的实例存储为值以用作互斥量。查找后,然后在互斥锁上进行同步。


-1
投票

您可以在示例中尝试此操作:

String a = test.intern();

Java中的相等字符串并不总是指向同一实例,从不依赖于那个神话。

还要注意,字符串在Java中是不可变的,因此无需同步它们。

© www.soinside.com 2019 - 2024. All rights reserved.