Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Синхронизация по static обьекту


Автор: Andy_L20066 21.10.2009, 13:32
Доброго времени суток, 
есть вопрос.. начну сразу с кода:

1.
Код

public class Test {

private static final Object someObject = new Object();

public void doSomething()
{
        synchronized (someObject) {
                System.out.println(someObject.toString());
        }
}

}


Почитал тут немного в нете и как я понимаю в этом случае: только один Thread который использует любой инстанс класса Test может вызвать метод doSomething(), и если someObject не был бы статиком, тогда Threads c разными инстансами класса Test  могли бы вызвать doSomething, тоесть по сути синхронизация здесь будет иметь место для однотипных инстансов класса Test (instance-dependent) (дословно это звучит так: By using a static object as your monitor object, only one thread using ANY instance of the Test class can get into the sync block. If the monitor object was not a static object, other threads holding different instances of the Test class could get into the sync block)

2.
Код

public class Test {

private static final Object someObject = new Object();

public static void doSomething()
{
        synchronized (someObject) {
                System.out.println(someObject.toString());
        }
}

}

В этом варианте ничто не мешает двом тредам вызвать метод doSomething одновременно внезависимости от того какой инстанс класса Test они используют.... или я не прав? вот тут если кто может - подскажите что будет синхронизироватся?

3.
Код

public class Test {

private static final Object someObject = new Object();

public static void doSomething()
{
        synchronized (Test.class) {
                System.out.println(someObject.toString());
        }
}

}

В этом варианте как я понимаю у нас будет локатся клас 'Test.class', тоесть doSomething - не вызовется двома тредами одновременно никак.

Напишите кто что думает по этому поводу.

Автор: LSD 21.10.2009, 17:25
1. Нет в Java никаких static объектов! Есть только статические ссылки на объекты.

2. Первый и второй варианты не ничем не отличаются в плане многопоточного поведения. Только один поток сможет выполнить этот метод в один момент времени.

3. В третьем варианте синхронизация будет идти по объекту тика java.lang.Class (тот самый который возвращается testObject.getClass()). Разница с первыми двумя, только в том, что этот объект доступен извне и кто нибудь может в другом месте кода написать:
Код

synchronized (Test.class) {
    ....
}

и это заблокирует и doSomething() метод тоже.

Автор: Andy_L20066 21.10.2009, 17:56
на счет статик обьектов согласен... (я просто перевел то что было на англ. написано здесь http://stackoverflow.com/questions/314607/static-members-need-special-synchronization-blocks)

Тогда вопрос: 

если в многопоточном плане 1 и 2  не отличаются - то насчет того что написано о инстансах класса Test - это правда? Можешь обьяснить поподробнее? (By using a static object as your monitor object, only one thread using ANY instance of the Test class can get into the sync block. If the monitor object was not a static object, other threads holding different instances of the Test class could get into the sync block)


Автор: LSD 21.10.2009, 19:56
На самом деле смысл имеет только то, на каком объекте был вызвал synchronized, а уж был он получен из статик переменной, как инстанс синглетона (это как раз случай с Test.class) или еще как - совершенно неважно.
Код

public class Test {
    private static final Object lock = new Object();

    public static void foo() {
        synchronized (lock) {
            ...
        }
    }
}

Код

public class Test {
    private static final Object lock = new Object();

    public void foo() {
        synchronized (lock) {
            ...
        }
    }
}

Код

public class Test {
    private static Test instance = new Test();
    
    private final Object lock = new Object();
    
    
    private Test() {
    }

    public static Test getInstance() {
        return instance;
    }

    public void foo() {
        synchronized (lock) {
            ...
        }
    }
}

Код

public class Test {
    public void foo() {
        synchronized (Test.class) {
            ...
        }
    }
}

Во всех этих случаях метод foo() одновременно будет выполняться только одним потоком. Правда в последнем случае, может выйти так что вообще не один поток не сможет его вызвать т.к. кто-то в другом месте залочил объект. И последний случай эквивалентен:
Код

public class Test {
    public static synchronized void foo() {
        ...
    }
}

(ну за исключением того, что один метод статический, другой нет).

Автор: Andy_L20066 21.10.2009, 20:33
Спасибо за ответы... последнее высказивание о том что "кто-то в другом месте залочил обьект" означает что если у меня есть вот такое:
Код

public class Test {
    public void foo() {
        synchronized (Test.class) {
            ...
        }
    }
}


то в другом классе у меня может быть лок на том же классе:

Код

public class A {
    public void foo1() {
        synchronized (Test.class) {
            ...
        }
    }
}

Автор: LSD 22.10.2009, 13:51
Цитата(Andy_L20066 @  21.10.2009,  20:33 Найти цитируемый пост)
последнее высказивание о том что "кто-то в другом месте залочил обьект" означает что если у меня есть вот такое:
...
то в другом классе у меня может быть лок на том же классе:

Да. И методы foo() и foo1() одновременно будут выполняться только одним потоком.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)