A estrutura de bifurcação/junção é uma implementação da interface ExecorService, através da qual podemos implementar vários processos. O garfo/junção pode ser usado para dividir recursivamente uma grande tarefa em várias pequenas tarefas, com o objetivo de fazer pleno uso de todos os recursos para aprimorar o desempenho do aplicativo o máximo possível.
Como qualquer implementação da interface do ExecutSorService, o Fork/Junção também usa pools de threads para gerenciar threads de trabalhadores distribuídos. O que é único na estrutura do garfo/junção é que ele usa o algoritmo de roubo de trabalho. Através desse algoritmo, os threads de trabalhadores podem roubar outras tarefas de encadeamento ocupado para executar quando nada pode ser feito.
O núcleo da estrutura de garfo/junção é a classe ForkJoinpool, uma subclasse da classe AbstractExecTorService. O ForkJoinpool implementa o algoritmo principal de roubo de trabalho e pode executar o processamento do ForkJointask.
Uso básico
O primeiro passo no uso da estrutura do garfo/junção é escrever código que executa tarefas fragmentadas. O código a ser escrito é semelhante ao seguinte pseudo-código:
Se a tarefa for pequena o suficiente: execute a tarefa diretamente: corte a tarefa em duas pequenas tarefas para executar duas pequenas tarefas e aguardar o resultado
Use a subclasse ForkJointask para encapsular o código como acima. Geralmente, são usadas algumas classes fornecidas pelo JDK, incluindo o RecursiveTask (esta classe retornará um resultado) e Recursiveation.
Depois de preparar a subclasse ForkJointask, crie um objeto que represente todas as tarefas e passe -o para um método Invoke () de uma instância do ForkJoinpool.
De borrão para limpar
Para ajudar a entender como funciona a estrutura de garfo/junção, usamos um gabinete para ilustrar: por exemplo, embaçar uma imagem. Representamos a imagem usando uma matriz inteira, onde cada valor numérico representa a cor de um pixel. A imagem borrada também é representada por uma matriz do mesmo comprimento.
A execução do Blur é alcançada processando cada pixel representando a figura. Calcule a média de cada pixel e seus pixels circundantes (a média das três cores primárias de vermelho, amarelo e azul), e a variedade de resultados resultantes é a imagem borrada. Como a representação das imagens geralmente é uma grande matriz, todo o processo geralmente leva muito tempo. A estrutura do garfo/junção pode ser usada para alavancar as vantagens do processamento simultâneo em sistemas multiprocessadores para acelerar. Aqui está uma possível implementação:
pacote com.zhyea.robin; importar java.util.concurrent.recursiveation; classe pública Forkblur estende o recurso RecursivEction {private Int [] msource; private int mstart; Private Int Mlength; private Int [] mDestination; // manipulam o tamanho da janela; Precisa ser um número ímpar. private int mblurwidth = 15; public forkblur (int [] src, int start, int length, int [] dst) {msource = src; mstart = start; mlength = comprimento; mDestinação = DST; } Protected void computediretly () {int sidepixels = (mblurwidth - 1) / 2; for (int index = mstart; índice <mstart+mlength; index ++) {// calcule o valor médio. flutuar rt = 0, gt = 0, bt = 0; for (int mi = -SidePixels; mi <= sidepixels; mi ++) {int mindex = math.min (math.max (mi+index, 0), msource.length - 1); int pixel = msource [MINDEX]; rt += (float) ((pixel & 0x00FF0000) >> 16) / mblurwidth; gt += (float) ((pixel & 0x00000FF00) >> 8) / mblurwidth; bt += (float) ((pixel & 0x000000ff) >> 0) / mblurwidth; } // reorganize o pixel de destino. int dpixel = (0xff0000000) | (((int) RT) << 16) | (((int) gt) << 8) | (((int) bt) << 0); mDestinação [índice] = dpixel; }} ....}Agora implemente o método abstrato Compute (), no qual as duas operações difusas são implementadas, e dividindo uma tarefa em duas pequenas tarefas é implementada. Aqui, simplesmente decidimos se devemos executar a tarefa diretamente ou dividi -la em duas pequenas tarefas com base na duração da matriz:
estático protegido int sthshold = 100000; Protected void compute () {if (mlength <shreshold) {computedirectly (); retornar; } int split = mlength / 2; InvokeAll (New Forkblur (Msource, MStart, Split, MDestination), New Forkblur (Msource, MStart + Split, Mlength - Split, MDestination)); }Como a implementação dos métodos acima é definida em uma subclasse de recursivamento, as tarefas podem ser criadas e executadas diretamente em um ForkJoinpool. As etapas específicas são as seguintes:
1. Crie um objeto que represente a tarefa a ser executada:
// src representa uma matriz de pixels da imagem de origem // dst representa os pixels da imagem gerada Forkblur fb = new Forkblur (src, 0, src.length, dst);
2. Crie uma instância do ForkJoinpool que execute a tarefa:
ForkJoinPool pool = new ForkJoinPool();
3. Execute a tarefa:
pool.invoke(fb);
O código -fonte também contém algum código para criar a imagem de destino. Para detalhes, consulte o exemplo do Forkblur.
Implementação padrão
Para usar a estrutura do garfo/junção para executar tarefas simultâneas em sistemas multi-core, de acordo com algoritmos personalizados, é claro, você precisa implementar classes personalizadas (como a classe Forkblur que implementamos antes). Além disso, alguns recursos da estrutura do garfo/junção foram amplamente utilizados no Javase. Por exemplo, o método parallelSort () da classe java.util.arrays in java8 usa a estrutura do garfo/junção. Para detalhes, consulte a documentação da API Java.
Outra implementação da estrutura de bifurcação/junção está no pacote java.util.streams, que também faz parte do recurso Lambda do Java8.