Java锁:如何在同步块中完成监视器锁的相等性检查?

2022-09-04 08:02:51

当你在一个对象上有几个块(比如说)那么Java如何检查所有这些块是相同还是不同?synchronizedobjobj

例如:

public static f() {
    synchronized ("xyz") {
        ...
    }
}

如果上述函数由两个线程同时调用,它们会阻止另一个线程吗?请注意,每个线程都将获得一个新的对象实例。fString

为了检查这一点,我写了下面的测试代码,看起来上面的块确实会起作用,但是还有其他意想不到的结果。

public class Test {

    public static void main(String[] args){

        new Thread() {
            public void run() {
                //f1("A", new X());
                f1("A", "Str");
            }
        }.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //f1("B", new X());
        f1("B", "Str");
    }

    public static void f1(String a, Object x) {
        synchronized(x) {
            System.out.println("f1: " + a);
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("f1: " + a + " DONE");
        }
    }

    private static class X {
        public boolean equals(Object o) {
            System.out.println("equals called");
            return true;
        }

        public int hashCode() {
            System.out.println("hashCode called");
            return 0;
        }
    }

}

如果运行上述代码,您将获得以下输出:-

f1: A
f1: A DONE
f1: B
f1: B DONE

但是,如果我注释和行并取消注释它们上面的行,那么结果是:-f1("A", "Str");f1("B", "Str");

f1: A
f1: B
f1: A DONE
f1: B DONE

由于该版本有效,所以我期望Java可能使用检查块,或者也许,但从第二次测试来看,情况似乎并非如此。StrequalssynchronizedhashCode

是特例吗?String


答案 1

否,Java 不用于锁定监视器。equals

锁位于对象实例本身上。因此,在某种程度上,如果您愿意,它使用“==”(但实际上,这不是它的实现方式。每个对象都有一个用于当前锁所有者的特殊插槽)。

字符串没有特殊情况。

但是,字符串发生的情况是字符串文本被池化,并且如果您多次具有相同的文本,则将导致相同的实例(而创建不同的实例,就像这样)。如果您调用“新”字符串,您可能会看到相同的效果。new Xnew Stringintern


答案 2

推荐