Maison > Java > javaDidacticiel > le corps du texte

Analyse de quatre utilisations du pool de threads Java

高洛峰
Libérer: 2017-01-23 16:26:04
original
1455 Les gens l'ont consulté

Cet article analyse quatre utilisations du pool de threads Java pour votre référence. Le contenu spécifique est le suivant

1 Inconvénients du nouveau thread

Pour effectuer une tâche asynchrone, utilisez-vous toujours. nouveau fil comme suit ?

new Thread(new Runnable() {
 
  @Override
  public void run() {
    // TODO Auto-generated method stub
    }
  }
).start();
Copier après la connexion

Ensuite, vous avez trop d'outs. Les inconvénients du nouveau Thread sont les suivants :

a chaque fois qu'un nouveau Thread crée un objet, la performance est. pauvre.
b. Les threads manquent de gestion unifiée, il peut y avoir un nombre illimité de nouveaux threads, se faire concurrence et occuper trop de ressources système, provoquant des plantages ou un MOO.
c. Manque de fonctions supplémentaires, telles que l'exécution planifiée, l'exécution périodique et l'interruption des threads.

Par rapport au nouveau Thread, les avantages des quatre pools de threads fournis par Java sont :

a. Réutilisez les threads existants, réduisez le coût de création et de destruction d'objets et obtenez de bonnes performances.
b. Il peut contrôler efficacement le nombre maximum de threads simultanés, améliorer l'utilisation des ressources système et éviter une concurrence et une congestion excessives des ressources.
c. Fournit des fonctions telles que l'exécution planifiée, l'exécution périodique, le thread unique et le contrôle de concurrence.

2. Pool de threads Java

Java fournit quatre pools de threads via les exécuteurs, à savoir :

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. peut recycler de manière flexible les threads inactifs. S'il n'y a pas de thread recyclable, un nouveau thread sera créé.
newFixedThreadPool crée un pool de threads de longueur fixe, qui peut contrôler le nombre maximum de threads simultanés en excès qui attendront dans la file d'attente.
newScheduledThreadPool crée un pool de threads de longueur fixe qui prend en charge l'exécution de tâches planifiées et périodiques.
newSingleThreadExecutor crée un pool de threads à thread unique, qui utilisera uniquement un thread de travail unique pour exécuter les tâches, garantissant que toutes les tâches sont exécutées dans l'ordre spécifié (FIFO, LIFO, priorité).
(1)newCachedThreadPool :

Créez un pool de threads pouvant être mis en cache. Si la longueur du pool de threads dépasse les besoins de traitement, les threads inactifs peuvent être recyclés de manière flexible. S'il n'y a pas de recyclage, un nouveau thread sera créé. . L'exemple de code est le suivant :

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  for (int i = 0; i < 10; i++) {
    final int index = i;
  try {
    Thread.sleep(index * 1000);
  }
    catch (InterruptedException e) {
      e.printStackTrace();
  }
 
cachedThreadPool.execute(new Runnable() {
 
@Override
public void run() {
  System.out.println(index);
}
});
}
Copier après la connexion


Le pool de threads est infini Lorsque la deuxième tâche est exécutée, la première tâche est terminée. et sera répété Utilisez le thread qui exécute la première tâche au lieu de créer un nouveau thread à chaque fois.

(2)newFixedThreadPool :

Créez un pool de threads de longueur fixe, qui peut contrôler le nombre maximum de threads simultanés, et les threads en excès attendront dans la file d'attente. L'exemple de code est le suivant :

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
  for (int i = 0; i < 10; i++) {
  final int index = i;
 
  fixedThreadPool.execute(new Runnable() {
 
@Override
public void run() {
try {
  System.out.println(index);
  Thread.sleep(2000);
} catch (InterruptedException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  }
}
});
}
Copier après la connexion

Étant donné que la taille du pool de threads est de 3, chaque tâche est en veille pendant 2 secondes après la sortie de l'index, donc 3 nombres sont imprimés toutes les deux secondes.

Il est préférable de définir la taille du pool de threads de longueur fixe en fonction des ressources système. Tel que Runtime.getRuntime().availableProcessors(). Veuillez vous référer à PreloadDataCache.

(3)newScheduledThreadPool :

Créez un pool de threads de longueur fixe pour prendre en charge l'exécution de tâches planifiées et périodiques. L'exemple de code pour une exécution retardée est le suivant :

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
 scheduledThreadPool.schedule(new Runnable() {
 
@Override
public void run() {
  System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
Copier après la connexion

signifie une exécution retardée de 3 secondes.

L'exemple de code pour une exécution régulière est le suivant :

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
 
@Override
public void run() {
  System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
Copier après la connexion

signifie une exécution toutes les 3 secondes après un délai de 1 seconde.

ScheduledExecutorService est plus sûr et plus puissant que Timer

(4) newSingleThreadExecutor :

Créez un pool de threads à un seul thread, qui n'utilisera que le seul thread de travail pour exécuter les tâches. et assurez-vous que toutes les tâches sont exécutées dans l’ordre spécifié (FIFO, LIFO, priorité). L'exemple de code est le suivant :

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
 
@Override
public void run() {
  try {
    System.out.println(index);
  Thread.sleep(2000);
} catch (InterruptedException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
    }
}
  });
}
Copier après la connexion

Les résultats sont affichés dans l'ordre, ce qui équivaut à exécuter chaque tâche dans l'ordre.

La plupart des programmes GUI actuels sont monothread. Les threads uniques dans Android peuvent être utilisés pour les opérations de base de données, les opérations sur les fichiers, l'installation par lots d'applications, la suppression par lots d'applications et d'autres opérations qui ne sont pas adaptées à la concurrence mais peuvent provoquer un blocage des E/S et affecter la réponse du thread de l'interface utilisateur.

Le rôle du pool de threads :

Le rôle du pool de threads est de limiter le nombre de threads d'exécution dans le système.
Selon l'environnement du système, le nombre de threads peut être défini automatiquement ou manuellement pour obtenir le meilleur effet de fonctionnement ; moins de ressources système seront gaspillées, et davantage entraînera une congestion et une inefficacité du système. Utilisez le pool de threads pour contrôler le nombre de threads, et les autres threads font la queue. Une fois qu'une tâche est exécutée, la tâche la plus en avant dans la file d'attente est prise et l'exécution commence. S'il n'y a aucun processus en attente dans la file d'attente, cette ressource du pool de threads est en attente. Lorsqu'une nouvelle tâche doit être exécutée, s'il y a des threads de travail en attente dans le pool de threads, elle peut commencer à s'exécuter, sinon elle entrera dans la file d'attente ;

Pourquoi utiliser le pool de threads :

1. Réduisez le nombre de créations et de destructions de threads, chaque thread de travail peut être réutilisé et peut effectuer plusieurs tâches.

2. Vous pouvez ajuster le nombre de threads de travail dans le pool de threads en fonction de la capacité du système pour éviter que le serveur ne soit épuisé en raison d'une consommation excessive de mémoire (chaque thread nécessite environ 1 Mo de mémoire et le thread démarre Plus la mémoire est consommée, plus la mémoire sera consommée et éventuellement le système plantera).

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 juste un outil pour exécuter des threads. La véritable interface du pool de threads est ExecutorService.

Certaines des classes les plus importantes :

ExecutorService : la véritable interface du pool de threads.

ScheduledExecutorService : Semblable à Timer/TimerTask, il peut résoudre des problèmes nécessitant l'exécution répétée de tâches.

ThreadPoolExecutor : L'implémentation par défaut d'ExecutorService.

ScheduledThreadPoolExecutor : hérite de l'implémentation de l'interface ScheduledExecutorService de ThreadPoolExecutor, une implémentation de classe de planification de tâches périodiques.

要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在Executors类里面提供了一些静态工厂,生成一些常用的线程池。

1.newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

2.newFixedThreadPool

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

3.newCachedThreadPool

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,

那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

4.newScheduledThreadPool

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

实例代码

一、固定大小的线程池,newFixedThreadPool:

package app.executors;
 
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
 
/**
 * Java线程:线程池
 *
 * @author xiho
 */
public class Test {
  public static void main(String[] args) {
    // 创建一个可重用固定线程数的线程池
    ExecutorService pool = Executors.newFixedThreadPool(2);
    // 创建线程
    Thread t1 = new MyThread();
    Thread t2 = new MyThread();
    Thread t3 = new MyThread();
    Thread t4 = new MyThread();
    Thread t5 = new MyThread();
    // 将线程放入池中进行执行
    pool.execute(t1);
    pool.execute(t2);
    pool.execute(t3);
    pool.execute(t4);
    pool.execute(t5);
    // 关闭线程池
    pool.shutdown();
  }
}
 
class MyThread extends Thread {
  @Override
  public void run() {
    System.out.println(Thread.currentThread().getName() + "正在执行。。。");
  }
}
Copier après la connexion

输出结果:

pool-1-thread-1正在执行。。。
pool-1-thread-3正在执行。。。
pool-1-thread-4正在执行。。。
pool-1-thread-2正在执行。。。
pool-1-thread-5正在执行。。。
Copier après la connexion

改变ExecutorService pool = Executors.newFixedThreadPool(5)中的参数:ExecutorService pool = Executors.newFixedThreadPool(2),输出结果是:

pool-1-thread-1正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-2正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-2正在执行。。。
Copier après la connexion

从以上结果可以看出,newFixedThreadPool的参数指定了可以运行的线程的最大数目,超过这个数目的线程加进去以后,不会运行。其次,加入线程池的线程属于托管状态,线程的运行不受加入顺序的影响。

二、单任务线程池,newSingleThreadExecutor:

仅仅是把上述代码中的ExecutorService pool = Executors.newFixedThreadPool(2)改为ExecutorService pool = Executors.newSingleThreadExecutor();
输出结果:

pool-1-thread-1正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-1正在执行。。。
pool-1-thread-1正在执行。。。
Copier après la connexion

可以看出,每次调用execute方法,其实最后都是调用了thread-1的run方法。

三、可变尺寸的线程池,newCachedThreadPool:

与上面的类似,只是改动下pool的创建方式:ExecutorService pool = Executors.newCachedThreadPool();

输出结果:

pool-1-thread-1正在执行。。。
pool-1-thread-2正在执行。。。
pool-1-thread-4正在执行。。。
pool-1-thread-3正在执行。。。
pool-1-thread-5正在执行。。。
Copier après la connexion

这种方式的特点是:可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。

四、延迟连接池,newScheduledThreadPool:

public class TestScheduledThreadPoolExecutor {
 
  public static void main(String[] args) {
 
    ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
 
    exec.scheduleAtFixedRate(new Runnable() {//每隔一段时间就触发异常
 
           @Override
 
           publicvoid run() {
 
              //throw new RuntimeException();
 
              System.out.println("================");
 
           }
 
         }, 1000, 5000, TimeUnit.MILLISECONDS);
 
    exec.scheduleAtFixedRate(new Runnable() {//每隔一段时间打印系统时间,证明两者是互不影响的
 
           @Override
 
           publicvoid run() {
 
              System.out.println(System.nanoTime());
 
           }
 
         }, 1000, 2000, TimeUnit.MILLISECONDS);
 
  }
 
}
Copier après la connexion

输出结果:

================
 
8384644549516
 
8386643829034
 
8388643830710
 
================
 
8390643851383
 
8392643879319
 
8400643939383
Copier après la connexion

   

以上就是本文的全部内容,希望对大家的学习有所帮助。

更多四种Java线程池用法解析相关文章请关注PHP中文网!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal