4
respostas

Como fazer para processar as notas em paralelo?

Olá! Estava tentando misturar os conceitos desta aula com os da anterior para processar as notas fiscais em paralelo. Tentei utilizar o seguinte código para criar um pool de 2 threads e conseguir processar duas notas por vez:

    public static void main(String[] args) {
        var fixedThreadPool = Executors.newFixedThreadPool(2);
        System.out.println("A thread do TesteEnvioNaoBloqueante é: " + Thread.currentThread().getName());
        NotaFiscal nota1 = new NotaFiscal("1) João", 39.89, LocalDate.now());
        NotaFiscal nota2 = new NotaFiscal("2) Maria", 39.89, LocalDate.now());
        NotaFiscal nota3 = new NotaFiscal("3) Bonner", 20.05, LocalDate.now());
        NotaFiscal nota4 = new NotaFiscal("4) Bilbo", 15.02, LocalDate.now());
        var notas = List.of(nota1, nota2, nota3, nota4);

        var publisher = new SubmissionPublisher<NotaFiscal>(fixedThreadPool, 2);
        var subscriber = new NotaFiscalSubscriber();
        publisher.subscribe(subscriber);
        notas.forEach(publisher::submit);

        System.out.println("Você irá receber a nota fiscal no seu email");
        var scanner = new Scanner(System.in);
        scanner.nextLine();
        scanner.close();
        publisher.close();
        fixedThreadPool.shutdown();
    }

Sendo que na classe NotaFiscalSubscriber, utilizo this.subscription.request(2) para requisitar duas mensagens por vez. No entanto, o processamento se dá de forma sequencial e vem sempre da thread pool-1-thread-2. O que preciso fazer para implementar tal paralelismo?

4 respostas

Johnny, boa tarde. Estou achando que pode ser por causa do foreach, ele deve mandar sequencial. Se vc fizer publisher.submit(nota1) e na linha debaixo publisher.submit(nota2), funciona?

Boa tarde, João! Tentei trocar o foreach por:

publisher.submit(nota1);
publisher.submit(nota2);
publisher.submit(nota3);
publisher.submit(nota4);

E o resultado foi o mesmo, mas agora a thread utilizada foi a pool-1-thread-1.

Engraçado que parece que o primeiro submit bloquea a execução, já que o println("Você irá receber a nota fiscal no seu email") é executado depois de processar a primeira nota. A saída é assim:

A thread do TesteEnvioNaoBloqueante é: main
Emitindo nota fiscal pela thread: pool-1-thread-1
Nota fiscal emitida 
Em nome de 1) João 
Na data de 2021-12-17 
Emitindo nota fiscal pela thread: pool-1-thread-1
Você irá receber a nota fiscal no seu email
Nota fiscal emitida 
Em nome de 2) Maria 
Na data de 2021-12-17 
Emitindo nota fiscal pela thread: pool-1-thread-1
Nota fiscal emitida 
Em nome de 3) Bonner 
Na data de 2021-12-17 
Emitindo nota fiscal pela thread: pool-1-thread-1
Nota fiscal emitida 
Em nome de 4) Bilbo 
Na data de 2021-12-17 

Tenta assim

NotaFiscal primeiraNotaFiscal = new NotaFiscal("João", 39.99, LocalDate.now());
        NotaFiscal segundaNotaFiscal = new NotaFiscal("Renata", 39.99, LocalDate.now());
        NotaFiscal terceiraNotaFiscal = new NotaFiscal("Paulo", 39.99, LocalDate.now());
        SubmissionPublisher<NotaFiscal> publisher = new SubmissionPublisher<>();
        NotaFiscalSubscriber subscriber = new NotaFiscalSubscriber();

        var notas = List.of(primeiraNotaFiscal, segundaNotaFiscal, terceiraNotaFiscal);

        publisher.subscribe(subscriber);
        notas.forEach(publisher::submit);
        System.out.println("Você irá receber a nota fiscal no seu e-mail");

        Scanner scan = new Scanner(System.in);
        scan.nextLine();
        scan.close();

        publisher.close();
    }

Se não me engano, para processar de forma paralela tu precisarias ter mais de um Subscriber.

Da forma que foi mostrado no vídeo, tu trabalha com mais de uma thread, utilizando a main para orquestrar o Publisher, e uma worker thread (daemon) para o Subscriber. Porém, se tu não tiver múltiplos Subscribers, sempre vai ser processado apenas pelo mesmo, criando uma fila e processando sequencialmente.

O problema é que o SubmissionPublisher é multicast, o que significa que ele envia todo o dataset (as mensagens, ou neste caso, lista de Notas Fiscais) para cada Subscriber, fazendo com que as notas fossem processadas em duplicidade. O jeito seria trocar para uma implementação de Publisher unicast, que enviaria a nota 1 para um Subscriber X, e ao invés de reenviar ela para o Y, manda a nota 2 para este.

Não pesquisei muito depois disso, e posso estar enganado, mas umas buscas no StackOverflow me trouxeram até aqui. Seria massa se o João Victor pudesse me dar um feedback sobre o que escrevi, pra ver se não entendi errado ahahahaha