Répertoire d'articles de la série
Le premier chapitre du pool de threads Android explique en langage simple (1) Le
deuxième chapitre du pool de threads Android explique en langage simple (2)
Premiers pas avec les pools de threads
Préface
Dans le développement Android, les tâches chronophages sont souvent traitées dans des threads non-UI. À ce stade, les threads sont nécessaires pour gérer les tâches asynchrones. Si un thread est créé à chaque fois et détruit après son exécution, il consommera un grand nombre de scènes qui nécessitent plusieurs threads pour être utilisés fréquemment. Perte de ressources et de performances. Et les threads sont faciles à faire indépendamment et difficiles à contrôler.
Afin de résoudre les inconvénients de l'utilisation des threads, le framework Executor est fourni en Java 1.5 pour découpler la soumission et l'exécution des tâches. La soumission des tâches est transférée à Runnable ou Callable, et le framework Executor est utilisé pour traiter les tâches. La classe d'implémentation principale du framework Executor est ThreadPoolExecutor
Un, la signification du pool de threads
Il existe de nombreux threads simultanés dans le programme. Si chaque création manuelle n'est effectuée que pendant une courte période et que la tâche se termine, la création et la destruction fréquentes de threads réduiront l'efficacité du système et réduiront l'efficacité de l'utilisation du processeur. Afin d'économiser des ressources et d'améliorer l'efficacité, Java fournit un pool de threads pour résoudre le problème.
Le pool de threads est en fait un conteneur qui contient plusieurs threads. Les threads peuvent être utilisés à plusieurs reprises, éliminant ainsi le besoin de créer fréquemment des objets thread, et il n'est pas nécessaire de créer des threads à plusieurs reprises et de consommer trop de ressources.
Deuxièmement, quels sont les avantages des pools de threads
- Réduire la consommation des ressources système et réduire la consommation causée par la création et la destruction de threads en réutilisant plusieurs fois les threads existants;
- Améliorer la vitesse de réponse du système Lorsqu'une tâche arrive, elle peut être exécutée immédiatement sans attendre la création d'un nouveau thread en réutilisant les threads existants;
- Améliorez la gérabilité des threads, ajustez le nombre de threads de travail en fonction de la capacité de charge du système pour éviter une utilisation excessive de la mémoire d'OOM (chaque thread consomme environ 1 Mo). En même temps, il y a trop de threads et le changement de processeur fréquent produira des quantités élevées Planification du coût du temps et réduction du temps de fragment de planification du processeur. Et vous pouvez utiliser le pool de threads pour allouer, régler et surveiller uniformément les threads.
- Fournir des fonctions plus puissantes, retarder le pool de threads de synchronisation.
Troisièmement, création de pool de threads
L'interface de niveau supérieur du pool de threads en Java est java.util.concurrent.Executor, mais au sens strict, Executor n'est pas un pool de threads, mais un outil pour exécuter des threads. L'interface réelle du pool de threads java.util.concurrent.ExecutorService.
Il est plus compliqué de configurer un pool de threads. Si vous n'êtes pas très clair sur le principe du pool de threads, il est très probable que le pool de threads configuré ne soit pas optimal, il est donc fourni dans la classe de fabrique de threads java.util.concurrent.Executors Certaines fabriques statiques génèrent des pools de threads couramment utilisés. La recommandation officielle est d'utiliser la classe d'ingénierie Executors pour créer des objets de pool de threads. Les exécuteurs sont des outils et des classes d'usine pour Executor, ExecutorService, ScheduledExecutorService, ThreadFactory et Callable.
Si ThreadPoolExecutor est créé, Executors appelle newFixedThreadPool, newSingleThreadExecutor et newCachedThreadPool pour créer des pools de threads qui sont tous de type ThreadPoolExecutor. Quel que soit le type de méthode de création de la classe Executors appelée, le constructeur de la classe ThreadPoolExecutor sera finalement appelé.
code montrer comme ci-dessous:
/**
*
* @param corePoolSize 保留在池中的线程数,即使*处于空闲状态,
* 除非设置了{@code allowCoreThreadTimeOut}
* @param maximumPoolSize 池中允许的最大线程数
* @param keepAliveTime 当线程数大于核心时,这是多余的空闲线程在终止之前等待新任务的最长时间。
* @param unit {@code keepAliveTime}参数的时间单位
* @param workQueue 在执行任务之前用于保留任务的队列。该队列将仅保存由{@code execute}方法提交的{@code Runnable} *任务。
* @param threadFactory 执行程序创建新线程时要使用的工厂
* @param handler 当执行被阻塞时要使用的处理程序,因为达到了线程界限和队列容量,注意它并不是一个我们常见的Handler
* @throws IllegalArgumentException 如果满足下列条件之一,则报IllegalArgumentException异常:
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException 如果 workQueue、threadFactory、handler之一为空,则报NullPointerException异常
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
}
Quatre, le constructeur en détail
paramètre | La description |
---|---|
corePoolSize | Le nombre de threads principaux. Lorsque le nombre de threads est inférieur à cette valeur, le pool de threads donnera la priorité à la création de nouveaux threads pour effectuer de nouvelles tâches |
maximumPoolSize | Le nombre maximum de threads que le pool de threads peut gérer |
keepAliveTime | Durée de vie des threads inactifs |
unité | Le paramètre keepAliveTime est l'unité du temps de survie du thread inactif. Il s'agit d'une classe énumérée |
workQueue | File d'attente de tâches, utilisée pour mettre en cache les tâches non exécutées |
threadFactory | Usine de filetage. Un nom plus significatif peut être défini pour le nouveau thread via l'usine |
gestionnaire | Stratégie de rejet. Lorsque le pool de threads et la file d'attente de tâches sont tous deux saturés, la stratégie de rejet est utilisée pour traiter les nouvelles tâches. La valeur par défaut est AbortPolicy, c'est-à-dire lancer une exception directement |
1. Le pool de threads corePoolSize
est vide par défaut et le thread ne sera créé que lorsque la tâche est soumise. Si le nombre de threads en cours d'exécution est supérieur à corePoolSize, des threads sont créés en fonction de la situation. Si vous appelez la méthode prestartAllcoreThread du pool de threads, le pool de threads créera et démarrera tous les threads principaux à l'avance pour attendre les tâches.
2. maximumPoolSize
Si la file d'attente des tâches est pleine et que le nombre de threads est inférieur au maximumPoolSize, le pool de threads créera toujours de nouveaux threads pour traiter les tâches
3. keepAliveTime
Lorsque le nombre de threads est supérieur au noyau, il s'agit du temps le plus long pendant lequel les threads inactifs redondants attendent de nouvelles tâches avant de s'arrêter, et ils seront recyclés après ce délai.
S'il existe de nombreuses tâches et que le temps d'exécution de chaque tâche est court, vous pouvez augmenter keepAliveTime pour améliorer l'utilisation des threads. En outre, si la propriété allowCoreThreadTimeOut est définie sur true, keepAliveTime sera également appliqué au thread principal.
4. L'unité de temps du paramètre TimeUnit
keepAliveTime. Les unités optionnelles sont les jours, les heures, les minutes, les secondes, les millisecondes, etc.
5. workQueue est
utilisé pour conserver la file d'attente des tâches avant d'exécuter des tâches. Cette file d'attente enregistrera uniquement les tâches exécutables soumises par la méthode d'exécution. La file d'attente des tâches est du type BlockingQueue, qui est une file d'attente de blocage.
6. ThreadFactory
peut utiliser la fabrique de threads pour définir un nom pour chaque thread créé. Dans des circonstances normales, il n'est pas nécessaire de définir ce paramètre.
7. Stratégie de rejet RejectedExecutionHandler
. Le gestionnaire à utiliser lorsque l'exécution est bloquée, car la limite de thread et la capacité de la file d'attente sont atteintes, notez qu'il ne s'agit pas d'un gestionnaire commun et que la valeur par défaut est AbordPolicy. Plusieurs de ses stratégies seront expliquées en détail dans le prochain blog.
Les paramètres de construction de ThreadPoolExecutor doivent remplir certaines conditions:
- Si l'une des situations suivantes se produit, une exception IllegalArgumentException sera lancée lors de la construction:
1. corePoolSize <0
2. keepAliveTime <0
3. maximumPoolSize <= 0
4. maximumPoolSize <corePoolSize - Si l'une des situations suivantes se produit, une exception NullPointerException sera levée pendant le processus de construction:
1. workQueue est nul
2. threadFactory est nul
3. gestionnaire est nul
Cinq, ThreadPoolExecutor commun
Différents types de ThreadPoolExecutor peuvent être créés en configurant directement ou indirectement les paramètres de ThreadPoolExecutor. Parmi eux, 4 types de pools de threads sont couramment utilisés: FixedThreadPool, CachedThreadPool, SingleThreadExecutor, ScheduledTheadPool.
1. FixedThreadPool
2. CachedThreadPool
3. SingleThreadExecutor
4. ScheduledTheadPool
Pour résumer
Pour des points de connaissances avancés tels que la stratégie de création de threads, la stratégie de recyclage des ressources de thread, la stratégie de mise en file d'attente des threads, la stratégie de rejet des threads, etc. dans le pool de threads , veuillez lire mon autre article de blog sur Android Thread Pool de manière simple (2)