Повторно заключване

Малко помощ, моля, разгледайте частта от кода по-долу.

public class Widget {
    public synchronized void doSomething() {
        ...
    }
}

public class LoggingWidget extends Widget {
    public synchronized void doSomething() {
        System.out.println(toString() + ": calling doSomething");
        super.doSomething();
    }
}

Четох, че когато се извика doSomething() в LoggingWidget, JVM ще се опита първо да получи заключване на LoggingWidget и след това на Widget.

Любопитно ми е да разбера причината. Дали защото JVM знае, че doSomething() има извикване към super.doSomething() или защото извикването на метод на подклас винаги ще придобие заключване и на суперкласа.

наздраве


person CaptainHastings    schedule 09.07.2009    source източник
comment
Трябва да публикувате препратка към мястото, където сте прочели това, защото не е вярно :-)   -  person oxbow_lakes    schedule 09.07.2009
comment
Наистина благодаря за помощта. Разбрах погрешно обяснението на повторното заключване. След като прочетох вашето обяснение, се върнах към източника (откъс от книгата Паралелност на практика) и сега има смисъл.   -  person CaptainHastings    schedule 09.07.2009


Отговори (5)


Грешите - ключалките се получават на ниво инстанция. Във вашия пример има само едно заключване, защото има само един екземпляр, създаден, когато кажете:

Widget w = new LoggingWidget

Можете да преглеждате ключалките (известни също като монитори, мутекси или семафори) като индивидуално „прикрепени“ към всеки екземпляр на обект в JVM.

Ако имахте друг метод synchronized в подкласа LoggingWidget, ще видите, че това е вярно. Не би било възможно да извикате този (нов) метод и метода doSomething едновременно [с различни нишки на един и същи обект].

Това важи и за друг synchronized метод в суперкласа (т.е. той не е засегнат по никакъв начин от методите, които са заменени).

person oxbow_lakes    schedule 09.07.2009

public synchronized void doSomething() {
    System.out.println(toString() + ": calling doSomething");
    super.doSomething();
}

е същото като:

public void doSomething() {
    synchronized (this) {
        System.out.println(toString() + ": calling doSomething");
        super.doSomething();
    }
}

Вие заключвате инстанцията, а не класа. Така че, когато се извика super.doSomething(), този екземпляр вече е заключен.

person bajafresh4life    schedule 09.07.2009

Има само един екземпляр за заключване, екземплярът на LoggingWidget, никога няма действителен екземпляр на Widget.

Заключването се получава, когато извикате LoggingWidget.doSomething() и тъй като вече имате заключване, когато извикате super.doSomething(), този метод се изпълнява както обикновено.

person Nick Holt    schedule 09.07.2009

Повторното влизане работи, като първо се придобие ключалката. Когато една нишка придобие заключването, това е известно в jvm. Когато въвеждат блок от код, който е синхронизиран с нишката, която в момента държи заключване, им е позволено да продължат без повторно придобиване на заключване. След това jvm увеличава брояча при всяко повторно влизане, като допълнително намалява при излизане от този блок, докато броят стане нула. Когато броят е нула, заключването се освобождава.

person Community    schedule 09.07.2009

B.Goetz – „JJava Concurrency in Practice“ ако вътрешните ключалки не бяха reentrant, извикването на super.doSomething никога нямаше да може да придобие заключването, защото щеше да се счита за вече задържано и нишката постоянно щеше да спре в очакване на заключване никога не може да придобие. Повторното влизане ни спасява от задънена улица в ситуации като тази.

person Ovidiu Lupas    schedule 10.07.2009