Java Academy · Lektion

Almindelige faldgruber

Rækkefølge, boxing og common pool

Lektion 4 af 413 trin

Almindelige faldgruber er en gratis Java Academy-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Java Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Java Academy-kurset indeholder 4 lektioner i alt.

Parallelitet giver ikke gratis hastighed

Et ekstra kald til parallel() kan gøre koden langsommere i stedet for hurtigere. Denne lektion gennemgår de klassiske faldgruber, så du kan undgå dem.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long sum = IntStream.rangeClosed(1, 1_000_000).parallel()
            .asLongStream().sum();
        System.out.println(sum);
    }
}

Faldgrube: Ekstraomkostninger ved rækkefølge

Operationer med bevaret rækkefølge som forEachOrdered eller limit tvinger trådene til at koordinere, hvilket udhuler fordelene ved parallel behandling.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        IntStream.rangeClosed(1, 5).parallel()
            .forEachOrdered(System.out::println);
    }
}

unordered kan hjælpe

Hvis rækkefølgen er ligegyldig, kan et kald til unordered() få kørselssystemet til at springe arbejdet med rækkefølgen over og parallelisere mere frit.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long count = IntStream.rangeClosed(1, 1_000_000).parallel()
            .unordered()
            .filter(n -> n % 5 == 0)
            .count();
        System.out.println(count);
    }
}

Faldgrube: Skjult boxing

Brug af Stream<Integer> parallelt mangedobler omkostningen ved boxing på tværs af tråde. Foretræk primitive streams til numerisk parallel behandling.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long sum = IntStream.rangeClosed(1, 1_000_000).parallel().asLongStream().sum();
        System.out.println(sum);
    }
}

Faldgrube: Den delte fælles pulje

Alle parallelle streams deler én ForkJoinPool.commonPool(). En lang parallel opgave kan udsulte andre opgaver i den samme JVM, herunder andre dele af dit program.

import java.util.concurrent.ForkJoinPool;

public class Main {
    public static void main(String[] args) {
        System.out.println(ForkJoinPool.commonPool().getParallelism());
    }
}

Isolér arbejde i en brugerdefineret pulje

For at holde tungt arbejde væk fra den fælles pulje skal du køre den parallelle stream i din egen ForkJoinPool.

import java.util.concurrent.ForkJoinPool;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) throws Exception {
        ForkJoinPool pool = new ForkJoinPool(2);
        long sum = pool.submit(() ->
            IntStream.rangeClosed(1, 1_000_000).parallel().asLongStream().sum()
        ).get();
        pool.shutdown();
        System.out.println(sum);
    }
}

Faldgrube: Kilder, der er svære at opdele

LinkedList, Stream.iterate og BufferedReader.lines opdeles dårligt. Parallel behandling af dem giver ofte kun lille eller negativ fordel.

import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        long n = Stream.iterate(1, x -> x + 1)
            .limit(100_000)
            .parallel()
            .filter(x -> x % 2 == 0)
            .count();
        System.out.println(n);
    }
}

Faldgrube: Lambdaer med tilstand

Lambdaer, der læser eller skriver ekstern tilstand, opfører sig ikke-deterministisk parallelt. Hold dem tilstandsløse for at få ensartede resultater.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int sum = IntStream.rangeClosed(1, 100).parallel()
            .map(n -> n + 1)
            .sum();
        System.out.println(sum);
    }
}

Faldgrube: findFirst kontra findAny

findFirst skal respektere rækkefølgen, hvilket medfører ekstraomkostninger parallelt. Hvis et vilkårligt matchende element er tilstrækkeligt, kan du bruge findAny.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int found = IntStream.rangeClosed(1, 1_000_000).parallel()
            .filter(n -> n % 99991 == 0)
            .findAny()
            .getAsInt();
        System.out.println(found);
    }
}

Faldgrube: Billige operationer på små datamængder

Ved meget små samlinger eller trivielt arbejde overstiger ekstraomkostningerne ved opdeling og sammenfletning enhver gevinst. Forbliv sekventiel.

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> small = List.of(1, 2, 3, 4);
        int sum = small.stream().mapToInt(Integer::intValue).sum();
        System.out.println(sum);
    }
}

Faldgrube: Dyr sammenfletning i indsamlere

Indsamlere med dyre sammenfletningstrin, f.eks. ved opbygning af store sorterede strukturer, kan udligne fordelene ved parallel behandling. Simple sammenlægninger kan flettes billigt.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long total = IntStream.rangeClosed(1, 1_000_000).parallel()
            .mapToLong(n -> n)
            .sum();
        System.out.println(total);
    }
}

Hurtigt tjek

Hvorfor kan findFirst være langsommere end findAny på en parallel stream?

Opsummering

Du har lært de almindelige faldgruber ved parallel behandling:

  • Rækkefølge (forEachOrdered, limit, findFirst) medfører koordinationsomkostninger; brug unordered eller findAny, når det er muligt.
  • Boxing mangedobler omkostningerne; foretræk primitive streams.
  • Den delte fælles pulje kan blive udsultet; isolér tungt arbejde i en brugerdefineret ForkJoinPool.
  • Kilder, der er svære at opdele, små datamængder og dyre sammenfletninger underminerer alle parallelitet.
Gratis at komme i gang

Lær Java med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
104
Lektioner
374

Ofte stillede spørgsmål

Er lektionen “Almindelige faldgruber” gratis?

Ja — hele teksten til “Almindelige faldgruber” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Java Academy-kurset, skal du opgradere til CoddyKit PRO. Java Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Almindelige faldgruber”?

Rækkefølge, boxing og common pool Du øver dig i Java Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Java Academy?

Der kræves ingen tidligere erfaring. Java Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.

Hvor lang tid tager lektionen “Almindelige faldgruber”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Java Academy-lektion?

Ja. Alle Java Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Oprettelse af parallelle streams
  2. Hvornår parallelitet hjælper
  3. Trådsikkerhed og sideeffekter
  4. Almindelige faldgruber
← Tilbage til Java Academy