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

13

当你在一个对象(比如说obj)上拥有多个synchronized代码块时,Java 是如何检查这些obj是相同的还是不同的呢?

例如:

public static f() {
    synchronized ("xyz") {
        ...
    }
}
如果两个线程同时调用上述函数f,它们会阻塞对方吗?请注意,每个线程都会获得一个新的String对象实例。 为了检查这个问题,我编写了以下测试代码,看起来似乎上面的代码块工作正常,但是却出现了其他意外情况。
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

由于 Str 版本有效,因此我认为 Java 可能会使用 equals 检查 synchronized 块,或者可能会使用 hashCode,但从第二个测试中看来,情况并非如此。

String 是否是一个特例?

1个回答

24

不,Java并没有使用equals来进行锁监视。

锁是放在对象实例本身上的。因此,某种程度上它使用"=="(但实际上它并不是这样实现的。每个对象都有一个特殊的插槽用于当前锁所有者)。

对于String类型,也没有特殊情况。

然而,对于字符串常量,它们会被汇集到一起,如果你有多个相同的常量,它们将指向同一个实例(而new Xnew String则会创建不同的实例)。如果在你的“new”字符串上调用intern方法,你可能会看到相同的效果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接