Explicação detalhada do princípio subjacente do conjunto de encadeamentos simultâneos Java e análise de código-fonte

1. Conjunto de threads e comparação de desempenho de threads

No caso de thread único, a velocidade de processamento de tarefas é muito melhor em comparação com o desempenho do pool de threads. O pool de threads pode ser reutilizado internamente. Depois que o thread processa a tarefa, ele pode retornar ao pool de threads para processar outras tarefas, o que reduz bastante a destruição de encadeamentos e o tempo de criação.

Vários pools de encadeamentos que acompanham o java:

ExecutorService executorService = Executors.newCachedThreadPool(); 
ExecutorService executorService1 = Executors.newFixedThreadPool(100); 
ExecutorService executorService2 = Executors.newSingleThreadExecutor(); 
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);

Os parâmetros de construção do pool de threads acima são todos criados com ThreadPoolExecutor, mas os parâmetros usados ​​são diferentes.

O método de construção usado por newCachedThreadPool: parâmetros correspondentes (número de threads principais, número máximo de threads, tempo de sobrevivência do thread, unidade de tempo de sobrevivência do thread, fila), newCachedThreadPool tem apenas 0 threads principais e o número de threads temporários pode ser infinito, então sua eficiência de execução é muito alta, SynchronousQueue é um típico modelo produtor-consumidor, o que equivale a uma empresa de terceirização.

new ThreadPoolExecutor(0, Integer.MAX_VALUE, 
                              60L, TimeUnit.SECONDS, 
                              new SynchronousQueue<Runnable>())
O método de construção usado por newCachedThreadPool: o número de threads principais e o número de threads temporários são personalizados. A fila LinkedBlockingQueue é uma fila de bloqueio ilimitada, o que equivale a aguardar o processamento da tarefa indefinidamente, mas a eficiência é muito baixa. Equivale a uma empresa estatal. 
new ThreadPoolExecutor(nThreads, nThreads, 
                              0L, TimeUnit. MILLISECONDS, 
                              new LinkedBlockingQueue<Runnable>())
O método de construção usado por newSingleThreadExecutor: o número de threads principais e o número de threads temporários são 1, o que equivale a uma pessoa lidando com inúmeras tarefas. A eficiência é muito rápida quando as tarefas podem ser processadas rapidamente, mas será lenta quando as tarefas precisam ser processadas. Parece muito ineficiente. É equivalente a uma empresa privada, e tudo é feito por uma pessoa. 
novo FinalizableDelegatedExecutorService 
    (novo ThreadPoolExecutor(1, 1, 
                            0L, TimeUnit. MILLISECONDS, 
                            novo LinkedBlockingQueue<Runnable>()))

O pool de encadeamentos com maior probabilidade de ter OOM: newCachedThreadPool, que não é uma fila ilimitada, relatará OOM quando atingir o valor máximo de memória

Os três casos anteriores não são recomendados pelas especificações de Ali, mas os três acima podem ser usados ​​em empresas que não conseguem atingir o valor máximo de memória. Ali recomenda o pool de threads personalizado ThreadPoolExecutor

 1.1 Comparação de pools de threads na prática

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadDemo {

    public static void main(String[] args) {

        //定义3个线程池
        ExecutorService executorService = Executors.newCachedThreadPool();//很快
        ExecutorService executorService1 = Executors.newFixedThreadPool(100);//不快不慢
        ExecutorService executorService2 = Executors.newSingleThreadExecutor();//最慢

        //定义100个任务给线程池处理对比处理性能
        long begin = System.currentTimeMillis();
        for(int i=0;i<100;i++){
            executorService2.submit(new Task());
        }
        executorService.shutdown();
        long end = System.currentTimeMillis();
        System.out.println("处理时间:"+(end-begin)/1000+"秒");
    }
}

class Task implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"处理完任务");

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }
}

1.2 Combate ThreadPool Executor

/**
 * 第31个任务会拒绝任务
 */
public class ThreadDemo {

    public static void main(String[] args) {

        //定义ThreadPoolExecutor
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 30, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10));
        //定义100个任务给线程池处理对比处理性能
        long begin = System.currentTimeMillis();
        for(int i=0;i<100;i++){
            threadPoolExecutor.submit(new Task());
        }
        threadPoolExecutor.shutdown();
        long end = System.currentTimeMillis();
        System.out.println("处理时间:"+(end-begin)/1000+"秒");
    }
}

class Task implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"处理完任务");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

1.3  Pergunta 1 da entrevista: Parâmetros do conjunto de encadeamentos personalizados

public ThreadPoolExecutor(int corePoolSize, 
                          int maximumPoolSize, 
                          long keepAliveTime, 
                          unidade TimeUnit, 
                          BlockingQueue<Runnable> workQueue, 
                          ThreadFactory threadFactory, 
                          manipulador RejectedExecutionHandler) {
   
   

corePoolSize: número de threads principais

int maximumPoolSize: o número máximo de threads

long keepAliveTime: tempo de sobrevivência do encadeamento temporário

Unidade TimeUnit: unidade de sobrevivência de thread temporária

BlockingQueue<Runnable> workQueue: fila de tarefas

ThreadFactory threadFactory: classe de fábrica personalizada geral

Manipulador RejectedExecutionHandler: estratégia de rejeição, existem 4 definições, geralmente podemos personalizar a estratégia de rejeição

AbortPolicy: RejectedExecutionException é lançada por padrão para rejeitar a tarefa 
DiscardPolicy: Abandona a tarefa 
DiscardOldestPolicy: Lança a tarefa mais antiga pela estrutura da fila 
CallerRunsPolicy: A thread que chama o método execute executa a tarefa

1.4  Esquema de Execução de Análise de Código-Fonte do Pool de Perguntas da Entrevista (TODO) 

1.5 A diferença entre os métodos submit() e execute nas perguntas da entrevista (TODO)

A diferença entre enviar e executar: Existe um conceito de prioridade de envio e prioridade de execução no encadeamento, e a prioridade de envio é maior que a prioridade de execução. 
1. O método execute está no método submit. 
2. O método submit retornará uma função genérica Future, mas execute não retornará

 

 

1.6 A diferença entre offer() e add() em perguntas de entrevista

Ambos add e offer são métodos para adicionar tarefas à fila de tarefas.A diferença é que o método add não lança uma exceção, enquanto o offer lançará uma exceção de interrupção.Esta é a única diferença entre eles.

 

 

1.7 newScheduledThreadPool(TODO)

1.7.1 combate newScheduledThreadPool (TODO)

1.7.2 Análise do código-fonte (TODO)

1.8 Política de Negação Personalizada

Há duas maneiras de personalizar a política de rejeição:

//Estratégia de rejeição personalizada 
RejectedExecutionHandler rejeitedExecutionHandler = new RejectedExecutionHandler() { 
    @Override 
    public void failedExecution(Runnable r, ThreadPoolExecutor executor) { 
        System.out.println("Estratégia de rejeição personalizada, pode ser armazenada no banco de dados"); } 
    } 
;

O segundo método: implemente a interface RejectedExecutionHandler e reescreva o método rejeitadoExecution.

import java.util.concurrent.*;

/**
 * 第31个任务会拒绝任务
 */
public class ThreadDemo {

    public static void main(String[] args) {

        //自定义拒绝策略
        RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.out.println("自定义拒绝策略,可以存入数据库");
            }
        };

        //定义ThreadPoolExecutor
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 30, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10),rejectedExecutionHandler);
        //定义100个任务给线程池处理对比处理性能
        long begin = System.currentTimeMillis();
        for(int i=0;i<100;i++){
            threadPoolExecutor.submit(new Task());
        }
        threadPoolExecutor.shutdown();
        long end = System.currentTimeMillis();
        System.out.println("处理时间:"+(end-begin)/1000+"秒");
    }
}

class Task implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"处理完任务");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

Acho que você gosta

Origin blog.csdn.net/qq_21575929/article/details/124939077
Recomendado
Clasificación