Tear do projeto OpenJDK

Tear do projeto OpenJDK

1. Visão geral

Neste artigo, daremos uma olhada rápida emProject Loom. Em essência,the primary goal of Project Loom is to support a high-throughput, lightweight concurrency model in Java.

2. Projeto tear

O Project Loom é uma tentativa da comunidade OpenJDK de introduzir uma construção de simultaneidade leve no Java. Até agora, os protótipos do Loom introduziram uma mudança na JVM e na biblioteca Java.

Embora ainda não haja um lançamento agendado para o Loom, podemos acessar os protótipos recentes emProject Loom’s wiki.

Antes de discutirmos os vários conceitos do Loom, vamos discutir o modelo de simultaneidade atual em Java.

3. Modelo de simultaneidade de Java

Atualmente,Thread representa a abstração central da simultaneidade em Java. Essa abstração, junto com outrosconcurrent APIs, torna mais fácil escrever aplicativos simultâneos.

No entanto, como o Java usa os threads do kernel do sistema operacional para a implementação, ele falha em atender aos requisitos atuais de simultaneidade. Existem dois grandes problemas em particular:

  1. Threads cannão corresponde à escala da unidade de simultaneidade do domínio. Por exemplo, os aplicativos geralmente permitem até milhões de transações, usuários ou sessões. No entanto, o número de threads suportados pelo kernel é muito menor. Assim, aThread for every user, transaction, or session is often not feasible.

  2. A maioria dos aplicativos simultâneos precisa de alguma sincronização entre os threads para cada solicitação. Devido a isso,an expensive context switch happens between OS threads.

Uma possível solução para esses problemas éthe use of asynchronous concurrent APIs. Exemplos comuns sãoCompletableFutureeRxJava. Contanto que tais APIs não bloqueiem o thread do kernel, ele fornece ao aplicativo uma construção de simultaneidade mais refinada sobre os threads. Java

Por outro lado,such APIs are harder to debug and integrate with legacy APIs. E, portanto, há uma necessidade de uma construção de simultaneidade leve, independente dos threads do kernel.

4. Tarefas e agendadores

Qualquer implementação de um encadeamento, leve ou pesado, depende de duas construções:

  1. Tarefa (também conhecida como continuação) - Uma sequência de instruções que podem se suspender por alguma operação de bloqueio

  2. Agendador - Para atribuir a continuação à CPU e reatribuir a CPU a partir de uma continuação em pausa

Atualmente,Java relies on OS implementations for both the continuation and the scheduler.

Agora, para suspender uma continuação, é necessário armazenar toda a pilha de chamadas. E da mesma forma, recupere a pilha de chamadas na retomada. Since the OS implementation of continuations includes the native call stack along with Java’s call stack, it results in a heavy footprint.

Um problema maior, porém, é o uso do agendador do SO. Uma vez que o planejador é executado no modo kernel, não há diferenciação entre os threads. E trata todas as solicitações de CPU da mesma maneira.

Este tipo de programação énot optimal for Java applications in particular.

Por exemplo, considere um encadeamento de aplicativo que executa alguma ação nas solicitações e depois transmite os dados para outro encadeamento para processamento adicional. Aqui,it would be better to schedule both these threads on the same CPU. Mas como o agendador é independente do segmento que solicita a CPU, isso é impossível de garantir.

O Projeto Loom propõe resolver isso por meio deuser-mode threads which rely on Java runtime implementation of continuations and schedulers instead of the OS implementation.

5. Fibras

Nos protótipos recentes do OpenJDK, uma nova classe chamadaFiber é introduzida na biblioteca junto com a classeThread.

Como a biblioteca planejada paraFibers é semelhante aThread, a implementação do usuário também deve permanecer semelhante. No entanto, existem duas diferenças principais:

  1. Fiber wouldwrap any task in an internal user-mode continuation. This would allow the task to suspend and resume in Java runtime instead of the kernel

  2. Um agendador de modo de usuário conectável (ForkJoinPool, por exemplo) seria usado

Vamos examinar esses dois itens em detalhes.

6. Continuações

Uma continuação (ou co-rotina) é uma sequência de instruções que podem render e ser retomadas pelo chamador posteriormente.

Toda continuação tem um ponto de entrada e um ponto de escoamento. O ponto de escoamento é onde foi suspenso. Sempre que o chamador retoma a continuação, o controle retorna ao último ponto de rendimento.

É importante perceberthat this suspend/resume now occurs in the language runtime instead of the OS. Portanto, evita a troca de contexto dispendiosa entre os threads do kernel.

Semelhante aos threads, o Project Loom visa suportar fibras aninhadas. Como as fibras dependem de continuações internamente, também devem suportar continuações aninhadas. Para entender isso melhor, considere uma classeContinuation que permite o aninhamento:

Continuation cont1 = new Continuation(() -> {
    Continuation cont2 = new Continuation(() -> {
        //do something
        suspend(SCOPE_CONT_2);
        suspend(SCOPE_CONT_1);
    });
});

Conforme mostrado acima, a continuação aninhada pode suspender a si mesma ou qualquer uma das continuações envolventes, passando uma variável de escopoPor este motivo,they are known as scoped continuations.

Uma vez que suspender uma continuação também exigiria que ela armazenasse a pilha de chamadas, também é um objetivo do projeto Loom adicionar recuperação de pilha leve enquanto retoma a continuação.

7. Agendador

Anteriormente, discutimos as deficiências do agendador do SO ao agendar threads relacionáveis ​​na mesma CPU.

Embora seja uma meta do Project Loom permitir planejadores conectáveis ​​com fibras,ForkJoinPool in asynchronous mode will be used as the default scheduler. 

ForkJoinPool muda emwork-stealing algorithm. Assim, todo encadeamento mantém um deque de tarefas e executa a tarefa a partir de sua cabeça. Além disso, qualquer thread inativo não bloqueia,waiting for the task and pulls it from the tail of another thread’s deque instead. 

A única diferença no modo assíncrono é quethe worker threads steal the task from the head of another deque.

ForkJoinPool adiciona uma tarefa agendada por outra tarefa em execução à fila local. Portanto, executando-o na mesma CPU.

8. Conclusão

Neste artigo, discutimos os problemas no modelo de simultaneidade atual do Java e as mudanças propostas porProject Loom.

Ao fazer isso, também definimos tarefas e agendadores e vimos comoFibers and ForkJoinPool could provide an alternative to Java using kernel threads.