Блокировки Java: как выполняется проверка на равенство для блокировок монитора в синхронизированном блоке?

Когда у вас есть пара блоков synchronized на объекте (скажем) obj, то как 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 особым случаем?


person AppleGrew    schedule 27.08.2012    source источник


Ответы (1)


Нет, Java не использует equals для мониторов блокировки.

Блокировка находится на самом экземпляре объекта. Таким образом, в некотором смысле он использует "==", если хотите (но на самом деле это не так. Каждый объект имеет специальный слот для текущего владельца блокировки).

Для String нет особого случая.

Что происходит со строками, так это то, что строковые литералы объединяются, и если у вас есть один и тот же литерал более одного раза, это приведет к одному и тому же экземпляру (тогда как new X создает разные экземпляры, как и new String). Если вы вызовете intern для своих "новых" строк, вы, вероятно, увидите тот же эффект.

person Thilo    schedule 27.08.2012