Maison  >  Article  >  Java  >  Explication détaillée du pool de threads Java

Explication détaillée du pool de threads Java

angryTom
angryTomavant
2019-11-26 15:05:413391parcourir

Explication détaillée du pool de threads Java

Présentation du pool de threads

1. Un pool de threads est un pool qui gère les threads, ce qui peut réduire la création. et la destruction des threads. La consommation de ressources provoquée

Parce qu'un thread est en fait un objet, vous devez passer par le processus de chargement de classe, détruire un objet et passer par le garbage collection GC. processus, qui nécessitent tous une surcharge de ressources.

2. Améliorez la vitesse de réponse. Lorsque la tâche arrive, par rapport à la suppression du fil du pool de threads, la création du fil vous-même est nettement plus lente

3. remettez le fil dans le pool une fois qu'il est épuisé, obtenant l'effet de réutilisation

(vidéo recommandée : tutoriel vidéo Java)

pool de threads. exécution

Métaphore

Les threads principaux sont comparés aux employés réguliers de l'entreprise

Les threads non essentiels sont comparés aux employés externalisés

Files d'attente bloquantes sont comparés aux pools de demandes

Les tâches de soumission sont comparées aux soumissions Exigences

Explication détaillée du pool de threads Java

Exécution formelle

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,
   BlockingQueue<Runnable> workQueue,
   ThreadFactory threadFactory,
   RejectedExecutionHandler handler)
corePoolSize     核心线程数
maximumPoolSize  线程池最大线程数
keepAliveTime    空闲线程存活时间
TimeUnit         线程空闲存活时间单位
workQueue        存放任务的阻塞队列
threadFactory    线程工厂
handler          饱和策略

● Soumettre une tâche et lorsque le nombre de threads principaux survivants dans le pool de threads est inférieur au nombre de threads corePoolSize, le pool de threads créera un thread principal pour gérer les tâches soumises.

● Si le nombre de threads principaux dans le pool de threads est plein, c'est-à-dire que le nombre de threads est égal à corePoolSize, une tâche nouvellement soumise sera placée dans la file d'attente des tâches workQueue et mise en file d'attente pour exécution.

● Lorsque le nombre de threads survivants dans le pool de threads est égal à corePoolSize et que la file d'attente des tâches workQueue est également pleine, déterminez si le nombre de threads atteint maximumPoolSize, c'est-à-dire si le nombre maximum de threads est full.Si ce n'est pas le cas, créez un non-core Le thread exécute la tâche soumise.

● Si le nombre actuel de threads atteint maximumPoolSize et que de nouvelles tâches arrivent, la politique de rejet sera utilisée directement.

Plusieurs stratégies de saturation

AbortPolicy         抛出一个异常,默认的
DiscardPolicy       直接丢弃任务
DiscardOldestPolicy 丢弃队列里最老的任务,将当前这个任务继续提交给线程池
CallerRunsPolicy    交给线程池调用所在的线程进行处理

Gestion des exceptions du pool de threads

En raison de l'apparition de tâches de traitement des threads lors de l'appel du pool de threads Les exceptions peuvent être interceptées par le pool de threads, de sorte que l'exécution de la tâche peut ne pas en être consciente, nous devons donc prendre en compte les exceptions du pool de threads.

Première méthode :

@Test
public void test1() throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 5; i++) {
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("name: " + Thread.currentThread().getName());
                    Object a = null;
                    System.out.println(a.hashCode());
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        });
    }
}

Méthode deux :

@Test
public void test2() throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 20; i++) {
        Future<?> future = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("name: " + Thread.currentThread().getName());
                Object a = null;
                System.out.println(a.hashCode());
            }
        });
        try {
            future.get();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

File d'attente de travail du pool de threads

Quantity ArrayBlockingQueue

● LinkedBlockingQueue

● SynchronousQueue

● DelayQueue

● PriorityBlockingQueue

==ArrayBlockingQueue==

● Initialiser un tableau d'un certain capacité

● Utiliser un verrou réentrant. Le verrouillage injuste est utilisé par défaut. L'entrée et la sortie de la file d'attente partagent un verrou

● est une conception limitée. Si la capacité est pleine, les éléments ne peuvent pas être. ajouté jusqu'à ce qu'un élément ait été supprimé

● Ouvrez une mémoire continue lors de son utilisation. Si la capacité initiale est trop grande, cela entraînera facilement un gaspillage de ressources. Si la capacité initiale est trop petite, elle échouera facilement. add.

==LinkedBlockingQueue==

● Utiliser la structure de données de liste chaînée

● Espace mémoire non contigu

● Utiliser deux verrous réentrants pour contrôler l'entrée et la sortie des éléments respectivement, et utiliser Condition pour se réveiller et sortir de la file d'attente entre les threads. L'attente de

Quantity est limitée. Dans la méthode de construction par défaut, la capacité est Integer.MAX_VALUE

=. =SynchronousQueue==

● La capacité interne est de 0

● Chaque opération de suppression doit attendre l'opération d'insertion

● Chaque opération d'insertion doit attendre l'opération de suppression

● Pour un élément, une fois qu'il y a un fil d'insertion et un fil de retrait, il sera rapidement Le fil d'insertion est remis au fil de retrait Ce conteneur est équivalent à un canal et ne stocke pas lui-même les éléments.

● Dans une file d'attente multitâche, c'est le moyen le plus rapide de traiter les tâches.

==PriorityBlockingQueue==

● Conception illimitée, mais la capacité dépend en fait des ressources du système

● Ajoutez des éléments, s'il y en a plus d'un, entrez le tri prioritaire

==DelayQueue==

● Conception sans bordure

● L'ajout (mettre) ne bloque pas, la suppression du blocage

● Les éléments ont un délai d'expiration

● Seuls les éléments expirés seront supprimés

Pools de threads couramment utilisés

● newFixedThreadPool (pool de threads avec un nombre fixe de threads)

● newCachedThreadPool (pool de threads qui peut mettre en cache les threads)

● newSingleThreadExecutor (pool de threads à un seul thread)

● newScheduledThreadPool (pool de threads pour une exécution planifiée et périodique)

==newFixedThreadPool ==

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

Caractéristiques

1 Le nombre de threads principaux est le même que le nombre maximum de threads

2. chose comme non Le temps d'inactivité, c'est-à-dire keepAliveTime est 0

3 La file d'attente de blocage est une file d'attente illimitée LinkedBlockingQueue

Mécanisme de fonctionnement :

. Explication détaillée du pool de threads Java

● Soumettre la tâche

● Si le nombre de threads est inférieur au thread principal, créez un thread principal pour exécuter la tâche

● Si le nombre de threads est égal au thread principal, ajoutez la tâche à la file d'attente de blocage LinkedBlockingQueue

● 如果线程执行完任务,去阻塞队列取任务,继续执行。

==newCachedThreadPool==

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

线程池特点

● 核心线程数为0

● 最大线程数为Integer.MAX_VALUE

● 阻塞队列是SynchronousQueue

● 非核心线程空闲存活时间为60秒

Explication détaillée du pool de threads Java

工作机制:

● 提交任务

● 因为没有核心线程,所以任务直接加到SynchronousQueue队列。

● 判断是否有空闲线程,如果有,就去取出任务执行。

● 如果没有空闲线程,就新建一个线程执行。

● 执行完任务的线程,还可以存活60秒,如果在这期间,接到任务,可以继续活下去;否则,被销毁。

使用场景

用于并发执行大量短期的小任务。

使用SynchronousQueue作为工作队列,工作队列本身并不限制待执行的任务的数量。但此时需要限定线程池的最大大小为一个合理的有限值,而不是Integer.MAX_VALUE,否则可能导致线程池中的工作者线程的数量一直增加到系统资源所无法承受为止。

如果应用程序确实需要比较大的工作队列容量,而又想避免无界工作队列可能导致的问题,不妨考虑SynchronousQueue。SynchronousQueue实现上并不使用缓存空间

==newSingleThreadExecutor==

线程池特点

● 核心线程数为1

● 最大线程数也为1

● 阻塞队列是LinkedBlockingQueue

● keepAliveTime为0

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}

工作机制

Explication détaillée du pool de threads Java

● 提交任务

● 线程池是否有一条线程在,如果没有,新建线程执行任务

● 如果有,讲任务加到阻塞队列

● 当前的唯一线程,从队列取任务,执行完一个,再继续取,一个人(一条线程)夜以继日地干活。

使用场景

适用于串行执行任务的场景,一个任务一个任务的执行

==newScheduledThreadPool==

线程池特点

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
}

● 最大线程数为Integer.MAX_VALUE

● 阻塞队列是DelayedWorkQueue

● keepAliveTime为0

● scheduleAtFixedRate() :按某种速率周期执行

● scheduleWithFixedDelay():在某个延迟后执行

工作机制

● 添加一个任务

● 线程池中的线程从 DelayQueue 中取任务

● 线程从 DelayQueue 中获取 time 大于等于当前时间的task

● 执行完后修改这个 task 的 time 为下次被执行的时间

● 这个 task 放回DelayQueue队列中

scheduleWithFixedDelay

● 无论任务执行时间长短,都是当第一个任务执行完成之后,延迟指定时间再开始执行第二个任务

scheduleAtFixedRate

● 在任务执行时间小于间隔时间的情况下,程序以起始时间为准则,每隔指定时间执行一次,不受任务执行时间影响

● 当执行任务时间大于间隔时间,此方法不会重新开启一个新的任务进行执行,而是等待原有任务执行完成,马上开启下一个任务进行执行。此时,执行间隔时间已经被打乱

本文来自php中文网,java教程栏目,欢迎学习!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer