Toon posts:

[Java] Try-finally en code reordering

Pagina: 1
Acties:

Verwijderd

Topicstarter
Stel we definieren de volgende methoden.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    public void funcA() {
        prepareSomethings(); //might throw an unchecked exception
        Resource resource = acquireResource(); //might also throw an unchecked exception
        try {
            doStuff(resource);
        } finally {
            resource.release();
        }
    }
    
    public void funcB() {
        prepareSomethings(); //might throw an unchecked exception
        Resource resource = null;
        try {
            resource = acquireResource(); //might also throw an unchecked exception
            doStuff(resource);
        } finally {
            if (resource != null) {
                resource.release();
            }
        }
    }

Vanuit eerste perspectief lijken funcA en funcB hetzelfde te functioneren. Overigens vind ik funcA er cleaner uitzien.

Wat ik me nu afvraag is het volgende. De compiler mag onder bepaalde voorwaarde code reordering uitvoeren. Mag de compiler dan van funcA het volgende maken:
code:
1
2
3
4
5
6
7
8
9
    public void funcA_compilerOptimized() {
        Resource resource = acquireResource(); //might also throw an unchecked exception
        prepareSomethings(); //might throw an unchecked exception
        try {
            doStuff(resource);
        } finally {
            resource.release();
        }
    }

Oftwel regel 2 en 3 omgedraaid van de oorspronkelijk code. Bij normale executie blijft het gedrag namelijk hetzelfde als de oorspronkelijke code. Echter, er zal een probleem optreden zodra er een resource is 'acquired' en er een runtime exceptie optreed in prepareSomethings(), zodat de resource nooit meer gereleased gaat worden!! (Immers, het try-finally block zal dan als geheel worden overgeslagen). Mag ik daarom stellen dat de compiler deze reordering nooit zal toepassen?

  • Standeman
  • Registratie: November 2000
  • Laatst online: 00:17

Standeman

Prutser 1e klasse

Ik denk wel dat je dat mag stellen anders was ik het probleem al tig keer tegen gekomen :)

Ik heb behalve ervaring, geen echte onderbouwing.

Maar in funcA kan er alsnog een runtime exception plaatsvinden voordat de try ingegaan wordt, namelijk als je een brakke implementatie van acquireResource hebt.

The ships hung in the sky in much the same way that bricks don’t.


Verwijderd

Topicstarter
Standeman schreef op donderdag 19 februari 2009 @ 16:09:
Ik denk wel dat je dat mag stellen anders was ik het probleem al tig keer tegen gekomen :)

Ik heb behalve ervaring, geen echte onderbouwing.

Maar in funcA kan er alsnog een runtime exception plaatsvinden voordat de try ingegaan wordt, namelijk als je een brakke implementatie van acquireResource hebt.
Dat van die brakke implementatie klopt. 'acquireResource()' moet uiteraard zelf de nodige bronnen opruimen zodra een resource niet geretourneerd kan worden. Immers, op een 'null' resource is het onmogelijk om een 'release()' functie aan te roepen.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-09 16:37

.oisyn

Moderator Devschuur®

Demotivational Speaker

Natuurlijk mag dat niet. Code reordening mag alleen als (vanuit een enkele thread gezien) de side-effects volledig overeenkomen, en je dus niet aan de hand van slechts de zichtbare bijwerkingen kunt bepalen in welke volgorde de individuele statements van de code zijn uitgevoerd. Dat kan bij een dergelijke opzet niet. Althans, in theorie alleen als code die logischerwijs voor het throw-statement staat maar nog niet is uitgevoerd alsnog wordt uitgevoerd voordat er andere code in de catch-handlers e.d. wordt gerund die eventueel wat met die side-effects kunnen doen (waardoor het dus niet meer uitmaakt of het wordt gereordered of niet).

In een enkele thread moet de code altijd het resultaat opleveren zoals jij het hebt opgeschreven. Oftewel, de volgende code:
Java:
1
2
3
4
5
6
7
8
void foo()
{
    int a = 10, b = 10;
    if (a == 10)
        return;
    if (b == 10)
        System.out.printLn("Hallo");
}

zal nooit "Hallo" uitvoeren.

Het enige moment waarop jij als programmeur rekening moet houden met code reordering is als je meerdere threads shared resources laat accessen. Anders niet.

[ Voor 14% gewijzigd door .oisyn op 19-02-2009 16:50 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
Dat vermoeden had ik ook al. Dat is wel een geruststellende gedachte.