Auteur : Prince Poulet Rôti
Source : https://developer.hs.net/thread/2134
Récemment, je regardais le "Manuel de développement Java Edition Taishan" publié dans la [Liste des librairies des développeurs] d'Alibaba Cloud (je pense que beaucoup de frères devraient savoir que le manuel de développement d'Alibaba Cloud est en fait devenu un incontournable pour de nombreux développeurs et frères. J'ai lire le livre), il y a une spécification sur les threads dedans, et c'est obligatoire, regardons d'abord les instructions
[Obligatoire] Les pools de threads ne sont pas autorisés à utiliser des exécuteurs pour créer
Pourquoi désactiver ? C'est expliqué ci-dessous, car le nombre de threads ou la longueur de la file d'attente est fixé à la valeur maximale, ce qui peut provoquer un OOM dans certains cas. Certains jeunes frères du développement diront que je n'ai jamais vu de tels paramètres dans les exécuteurs. Découvrez son code source découvrir.
une brève introduction
Nous savons tous que l'interface de niveau supérieur du pool de threads en Java est Executor, mais à proprement parler, Executor n'est pas un pool de threads, mais un outil pour exécuter des threads. La véritable interface du pool de threads est ExecutorService, qui est créée par Executor et retourne à ExecutorService, et il existe trois fonctions couramment utilisées (newWorkStealingPool, etc. sont rarement utilisées et ne seront pas expliquées), qui sont :
- newFixedThreadPool crée un pool de threads de longueur fixe, qui peut contrôler le nombre maximal de threads simultanés, et les threads en excès attendront dans la file d'attente.
- newSingleThreadExecutor crée un pool de threads à un seul thread qui n'utilise qu'un seul thread de travail pour exécuter des tâches, garantissant que toutes les tâches sont exécutées dans l'ordre spécifié (FIFO, LIFO, priorité).
- newCachedThreadPool crée un pool de threads pouvant être mis en cache. Si la longueur du pool de threads dépasse les besoins de traitement, il peut recycler de manière flexible les threads inactifs. S'il n'y a pas de récupération, de nouveaux threads sont créés.
Description de ThreadPoolExecutor
Collez d'abord le code source de ThreadPoolExecutor :
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
- corePoolSize => le nombre de threads principaux du pool de threads
- maximumPoolSize => nombre maximum de pools de threads
- keepAliveTime => temps de survie du thread inactif
- unité => unité de temps
- workQueue => la file d'attente tampon utilisée par le pool de threads
- threadFactory => la fabrique utilisée par le pool de threads pour créer des threads
- handler => la stratégie de traitement du pool de threads pour les tâches rejetées
Pour plus de détails, vous pouvez également consulter https://developer.hs.net/thread/2124
voir le code source
Tant de choses ont été dites ci-dessus, jetons un coup d'œil au code source, nous devrions le comprendre plus rapidement grâce au code source
newFixedThreadPool
Il y a deux méthodes newFixedThreadPool dans la classe Executors, mais la différence est qu'il y a un paramètre ThreadFactory supplémentaire, et ce paramètre a un impact limité sur les performances, donc nous ne le montrerons pas, seulement la première méthode de fonction
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- corePoolSize = maximumPoolSize = nThreads, nThreads est un paramètre d'entrée, ce qui signifie qu'une grande valeur peut être entrée, ce qui peut provoquer un OOM
- keepAliveTime = 0L, l'unité est la milliseconde
- workQueue est LinkedBlockingQueue. Il convient de noter ici qu'en raison de l'utilisation de LinkedBlockingQueue, il est facile de provoquer des exceptions OOM lorsque les ressources sont limitées.
newSingleThreadExecutor
newSingleThreadExecutor est également une méthode de la classe Executors
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService (
new ThreadPoolExecutor(1, 1, 0L,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
}
SingleThreadExecutor est un pool de threads à un seul thread avec un seul thread principal
- corePoolSize = maximumPoolSize = 1
- keepAliveTime = 0L, l'unité est la milliseconde
- WorkQueue utilise LinkedBlockingQueue, alors il aura des problèmes avec newFixedThreadPool, et comme le nombre de threads traités est inférieur, la capacité de traitement est pire et cela provoquera un OOM.
newCachedThreadPool
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
- corePoolSize = 0, le nombre de pools de threads principaux est 0
- maximumPoolSize = Integer.MAX_VALUE, le nombre maximal de pools de threads est Integer.MAX_VALUE.
Voyons quelle est la valeur de MAX_VALUE
public static final int MAX_VALUE = 0x7fffffff;
- keepAliveTime = 60L
- l'unité est la seconde
- workQueue est SynchronousQueue
Lorsqu'une tâche est soumise, corePoolSize est 0 et aucun thread principal n'est créé. SynchronousQueue est une file d'attente qui ne stocke pas d'éléments. On peut comprendre que la file d'attente est toujours pleine, de sorte que des threads non principaux seront éventuellement créés pour exécuter des tâches. Pour les threads non essentiels, ils seront recyclés lorsqu'ils seront inactifs pendant 60 secondes. Parce que Integer.MAX_VALUE est très grand, on peut considérer que les threads peuvent être créés à l'infini, ce qui est facile à provoquer des exceptions OOM dans le cas de ressources limitées
Résumer
De l'affichage ci-dessus, nous pouvons voir que
- La longueur de file d'attente de requêtes autorisée pour FixedThreadPool et SingleThreadExecutor est Integer.MAX_VALUE, ce qui peut accumuler un grand nombre de requêtes, provoquant des exceptions OOM
- Le nombre de threads que CachedThreadPool permet de créer est Integer.MAX_VALUE, ce qui peut créer un grand nombre de threads, provoquant des exceptions OOM
C'est pourquoi il est interdit d'utiliser des Executors pour créer des pools de threads, et il est recommandé de créer soi-même ThreadPoolExecutor
Bien sûr, les exécuteurs encapsulent réellement ThreadPoolExecutor, il est donc préférable d'utiliser directement ThreadPoolExecutor