Pool de threads exécuteurs pour la programmation simultanée

1. Présentation du pool de threads

1.1 Pool de threads:
"Thread pool", comme son nom l'indique, est un cache de threads. Thread est une ressource rare. S'il est créé sans restriction, il consommera non seulement les ressources système, mais réduira également la stabilité du système. Par conséquent, Java fournit un pool de threads pour les threads Allocation, réglage et surveillance unifiés
1.2 Introduction aux pools de threads
Dans le développement Web, le serveur doit accepter et traiter les requêtes, un thread est donc alloué pour traiter une requête. Si un nouveau thread est créé pour chaque requête, il est très facile à implémenter, mais il y a un problème: si le nombre de requêtes simultanées est très important, mais que le temps d'exécution de chaque thread est très court, alors des threads seront créés et détruit fréquemment et réduira considérablement l'efficacité du système. Il peut sembler que le serveur consacre plus de temps et de ressources système à la création de nouveaux threads et à la destruction de threads pour chaque requête qu'au traitement des requêtes utilisateur réelles. Existe-t-il donc un moyen d'exécuter une tâche sans être détruite, mais peut-on continuer à effectuer d'autres tâches? C'est le but du pool de threads. Le pool de threads fournit une solution au problème de la surcharge du cycle de vie des threads et du manque de ressources. En réutilisant des threads pour plusieurs tâches, la surcharge de création de threads est amortie sur plusieurs tâches.
1.3 Quand utiliser le pool de threads?

  • Le temps de traitement d'une seule tâche est relativement court
  • Le nombre de tâches à traiter est important
    1.4 Avantages du pool de threads
  • Réutilisez les threads existants, réduisez la surcharge de création et de mort des threads, et améliorez les performances
  • Améliorez la vitesse de réponse. Lorsque la tâche arrive, la tâche peut être exécutée immédiatement sans attendre la création du thread.
  • Améliorez la gérabilité des threads. Les threads sont des ressources rares. S'ils sont créés de manière illimitée, ils consommeront non seulement des ressources système, mais réduiront également la stabilité du système. Le pool de threads peut être utilisé pour une allocation, un réglage et une surveillance uniformes.

2. cadre de l'exécuteur

Diagramme de classe de l'exécuteur
L'interface Executor est la partie la plus élémentaire du framework de pool de threads. Elle définit une méthode d'exécution pour exécuter Runnable.
ExecutorService est une sous-interface générale; des méthodes importantes sont définies:

public interface ExecutorService extends Executor {
    
    

    //在完成已提交的任务后封闭办事,不再接管新任务
    void shutdown();

    //停止所有正在履行的任务并封闭办事
    List<Runnable> shutdownNow();

	//测试是否该ExecutorService已被关闭
    boolean isShutdown();
	//测试是否所有任务都履行完毕了
    boolean isTerminated();

    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

	//可用来提交Callable或Runnable任务,并返回代表此任务的Future对象
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

2.1 Il y a 5 états du pool de threads

RUNNING    = ­1 << COUNT_BITS; //高3位为111
SHUTDOWN   =  0 << COUNT_BITS; //高3位为000
STOP       =  1 << COUNT_BITS; //高3位为001
TIDYING    =  2 << COUNT_BITS; //高3位为010
TERMINATED =  3 << COUNT_BITS; //高3位为011

1 、 FONCTIONNEMENT

  1. Description de l'état: lorsque le pool de threads est à l'état RUNNING, il peut recevoir de nouvelles tâches et traiter les tâches ajoutées.
  2. Changement d'état: l'état d'initialisation du pool de threads est EN COURS D'EXÉCUTION. En d'autres termes, une fois le pool de threads créé, il est à l'état RUNNING et le nombre de tâches dans le pool de threads est de 0!
    2. ARRÊT
  3. Description de l'état: lorsque le pool de threads est à l'état SHUTDOWN, il ne reçoit pas de nouvelles tâches, mais peut traiter les tâches ajoutées.
  4. Changement d'état: lorsque l'interface shutdown () du pool de threads est appelée, le pool de threads passe de RUNNING -> SHUTDOWN.
    3. STOP
  5. Description de l'état: lorsque le pool de threads est à l'état STOP, il ne reçoit pas de nouvelles tâches, ne traite pas les tâches ajoutées et interrompt les tâches en cours de traitement.
  6. Changement d'état: lorsque l'interface shutdownNow () du pool de threads est appelée, le pool de threads passe de (RUNNING ou SHUTDOWN) -> STOP.
    4. RANGEMENT
  7. Description de l'état: Lorsque toutes les tâches sont terminées et que le «nombre de tâches» enregistré par ctl est égal à 0, le pool de threads devient TIDYING. Lorsque le pool de threads devient TIDYING, la fonction hook terminé () sera exécutée. terminated () est vide dans la classe ThreadPoolExecutor. Si l'utilisateur souhaite effectuer le traitement correspondant lorsque le pool de threads devient TIDYING, cela peut être réalisé en surchargeant la fonction terminated ().
  8. Changement d'état: lorsque le pool de threads est à l'état SHUTDOWN, la file d'attente de blocage est vide et les tâches exécutées dans le pool de threads sont également vides, ce sera SHUTDOWN -> TIDYING. Lorsque le pool de threads est à l'état STOP, lorsque les tâches exécutées dans le pool de threads sont vides, il sera STOP -> TIDYING.
    5. RÉSILIÉ
  9. Description de l'état: le pool de threads est complètement arrêté et passe à l'état TERMINATED.
  10. Changement d'état: lorsque le pool de threads est dans l'état TIDYING, après l'exécution de terminated (), il sera TIDYING -> TERMINATED.
    Les conditions pour entrer TERMINÉ sont les suivantes:
  • Le pool de threads n'est pas à l'état RUNNING;
  • L'état du pool de threads n'est ni l'état TIDYING ni l'état TERMINATED;
  • Si l'état du pool de threads est SHUTDOWN et que workerQueue est vide;
  • workerCount est égal à 0;
  • Le statut TIDYING a bien été défini.

3. Création du pool de threads:

parExécuteursIntroduction aux types de pools de threads créés par l'API:
3.1 Un nombre fixe de pools de threads

    /**
    *创建重复使用固定数量线程的线程池
	*使用提供的
	*在需要时创建新线程的ThreadFactory。在任何时候,
	*最多{@code nThreads}线程将处于活动处理状态
	*任务。如果在所有线程
	*活动,它们将在队列中等待线程
	*可用。如果任何线程在
	*在关闭之前执行,如果
	*需要执行后续任务。池中的线程将
	*存在,直到显式{@ Link ExcutoService }shutdown
    * shutdown}.
	*@param nThreads 线程池中的线程数
	*@param threadFactory创建新线程时要使用的工厂
	*@return 返回新创建的线程池
	*@threadFactory为空时抛出NullPointerException
	*如果{@code nThreads<=0},则@throws IllegalArgumentException
     */
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    
    
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

3.2 Pool de threads parallèles
C'est le pool de threads nouvellement ajouté dans la 1.8, vous pouvez voir que les opérations liées à ForkJoin sont principalement utilisées

    /**
     * 并行线程池
     * 作为其目标并行级别。
	 *@返回新创建的线程池
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
    
    
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

3. Pool de threads avec un seul thread
En fait, cela ne peut pas être appelé pool de threads, car il n'y a qu'un seul thread. Core thread = Maximum thread = 1, ceci est plus approprié pour les scénarios qui doivent garantir l'exécution séquentielle des tâches dans la file d'attente.

    /**
	*创建使用单个工作线程操作的执行器
	*从无限的队列中。(但请注意,如果
	*线程在执行之前由于失败而终止
	*关闭,如果需要执行新的
	*后续任务。)保证执行任务
	*按顺序,任何时候都不会有多个任务处于活动状态
	*给定的时间。与其他等价物不同
	*{@code newFixedThreadPool(1)}返回的执行器是
	*保证不可重新配置以使用其他线程。
     *
     * @return the newly created single-threaded Executor
     */
    public static ExecutorService newSingleThreadExecutor() {
    
    
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

4. Cache le pool de threads
Il crée des threads selon les besoins. Il n'y a pas de thread principal. Lorsqu'il n'y a pas de tâches dans les années 60, les threads survivants seront recyclés. Lorsqu'il y aura des tâches dans les années 60, il pourra réutiliser les threads existants. Notez que sa file d'attente de travail est SynchronousQueue, voici une brève introduction), chacune de ses opérations put doit attendre l'opération take, ce qui signifie que si la vitesse de production de la tâche est supérieure à la vitesse de consommation, alors il ne créera pas de nouveau thread . Ce pool de threads convient aux scénarios dans lesquels un grand nombre de petites tâches sont effectuées.

    /**
	*创建根据需要创建新线程的线程池,但是
	*将重用以前构造的线程
	*可用。这些池通常会提高性能
	*执行许多短期异步任务的程序。
	*对{@code execute}的调用将重用先前构造的
	*线程(如果可用)。如果没有现有线程可用,则新建
	*将创建线程并将其添加到池中。具有
	*60秒未使用被终止并从
	*缓存。因此,一个空闲时间足够长的池将
	*不消耗任何资源。请注意,与
	*属性,但有不同的详细信息(例如,超时参数)
	*可以使用{@link ThreadPoolExecutor}构造函数创建。
     * @return the newly created thread pool
     */
    public static ExecutorService newCachedThreadPool() {
    
    
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

5. Pool de threads retardés
ScheduledThreadPoolExecutor hérite de ThreadPoolExecutor, donc super sera finalement transféré au constructeur de ThreadPoolExecutor. On peut voir que le nombre maximum de threads est la valeur maximale de int et que la file d'attente de travail est DelayedWorkQueue. Le pool de threads convient pour exécuter des tâches retardées.

    /**
	*创建可以调度命令的单线程执行器
	*在给定的延迟后运行,或周期性地执行。
	*(但请注意,如果
	*线程在执行之前由于失败而终止
	*关闭,如果需要执行新的
	*后续任务。)保证执行任务
	*按顺序,任何时候都不会有多个任务处于活动状态
	*给定的时间。与其他等价物不同
	*{@code newScheduledThreadPool(1)}返回的执行器是
	*保证不可重新配置以使用其他线程。
	*@返回新创建的计划执行器
     */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    
    
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }
        public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
    
    
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
    }

Je suppose que tu aimes

Origine blog.csdn.net/qq_38130094/article/details/104165504
conseillé
Classement