0Pricing
Java Academy · Aula

Armadilhas comuns

Ordenação, empacotamento e o pool comum.

Armadilhas comuns é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.

O paralelismo não acelera tudo gratuitamente

Adicionar parallel() pode tornar o código mais lento, não mais rápido. Esta lição aborda as armadilhas clássicas para que você possa evitá-las.

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);
    }
}

Armadilha: custo adicional da ordenação

Operações ordenadas, como forEachOrdered ou limit, exigem coordenação entre linhas de execução, reduzindo os ganhos do paralelismo.

import java.util.stream.IntStream;

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

unordered pode ajudar

Se a ordem não for importante, chamar unordered() permite que o ambiente de execução ignore o trabalho de ordenação e paralelize com mais liberdade.

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);
    }
}

Armadilha: empacotamento implícito

Usar Stream<Integer> em paralelo multiplica o custo do empacotamento entre as linhas de execução. Prefira fluxos de tipos primitivos para trabalhos numéricos paralelos.

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);
    }
}

Armadilha: o conjunto comum compartilhado

Todos os fluxos paralelos compartilham um único ForkJoinPool.commonPool(). Uma tarefa paralela longa pode impedir o progresso de outras no mesmo JVM, incluindo outras partes do seu aplicativo.

import java.util.concurrent.ForkJoinPool;

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

Isolando o trabalho em um conjunto personalizado

Para manter o trabalho pesado fora do conjunto comum, envie o fluxo paralelo dentro do seu próprio 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);
    }
}

Armadilha: fontes difíceis de dividir

LinkedList, Stream.iterate e BufferedReader.lines são difíceis de dividir. Paralelizá-los frequentemente traz pouco ou nenhum benefício, ou até piora o desempenho.

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);
    }
}

Armadilha: expressões lambda com estado

Expressões lambda que leem ou escrevem em um estado externo comportam-se de maneira não determinística em paralelo. Mantenha-as sem estado para obter resultados consistentes.

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);
    }
}

Armadilha: findFirst versus findAny

findFirst precisa respeitar a ordem, adicionando custo ao processamento paralelo. Se qualquer elemento correspondente servir, use 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);
    }
}

Armadilha: operações baratas em dados pequenos

Para coleções minúsculas ou trabalhos triviais, o custo de dividir e combinar supera qualquer ganho. Mantenha o processamento sequencial.

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);
    }
}

Armadilha: combinação cara em coletores

Coletores com etapas de combinação caras, como os que constroem grandes estruturas ordenadas, podem anular os ganhos do paralelismo. Acumulações simples são combinadas com baixo custo.

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);
    }
}

Verificação rápida

Por que findFirst pode ser mais lento que findAny em um fluxo paralelo?

Recapitulação

Você aprendeu as armadilhas comuns do processamento paralelo:

  • A ordenação (forEachOrdered, limit, findFirst) adiciona custo de coordenação; use unordered ou findAny quando possível.
  • O empacotamento multiplica o custo; prefira fluxos de tipos primitivos.
  • O conjunto comum compartilhado pode impedir o progresso de outras tarefas; isole o trabalho pesado em um ForkJoinPool personalizado.
  • Fontes difíceis de dividir, dados pequenos e combinações caras prejudicam o paralelismo.

Perguntas Frequentes

A aula “Armadilhas comuns” é grátis?

Sim — o texto completo de “Armadilhas comuns” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.

O que vou aprender em “Armadilhas comuns”?

Ordenação, empacotamento e o pool comum. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Java Academy?

Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Armadilhas comuns”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Java Academy?

Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Criando streams paralelos
  2. Quando o paralelismo ajuda
  3. Segurança de threads e efeitos colaterais
  4. Armadilhas comuns
← Voltar para Java Academy