ExecutorService vs ThreadPoolExecutor using LinkedBlockingQueue
je travaille sur un projet multithread dans lequel je dois générer plusieurs threads pour mesurer les performances de bout en bout de mon code client, pendant que je fais des tests de charge et de Performance. J'ai donc créé le code ci-dessous qui utilise ExecutorService
.
ci-dessous se trouve le code avec ExecutorService
:
public class MultithreadingExample {
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(20);
for (int i = 0; i < 100; i++) {
executor.submit(new NewTask());
}
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
}
}
class NewTask implements Runnable {
@Override
public void run() {
//Measure the end to end latency of my client code
}
}
énoncé du problème:
maintenant je lisais un article sur Internet. J'ai découvert il y a ThreadPoolExecutor
. Donc, je me suis confondue avec qui je devriez être en utilisant.
Si je remplace mon code ci-dessus:
ExecutorService executor = Executors.newFixedThreadPool(20);
for (int i = 0; i < 100; i++) {
executor.submit(new NewTask());
}
à:
BlockingQueue<Runnable> threadPool = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor tpExecutor = new ThreadPoolExecutor(20, 2000, 0L, TimeUnit.MILLISECONDS, threadPool);
tpExecutor.prestartAllCoreThreads();
for (int i = 0; i < 100; i++) {
tpExecutor.execute(new NewTask());
}
cela fera toute la différence? J'essaie de comprendre quelle est la différence entre mon code d'origine en utilisant ExecutorService
et le nouveau code collé avec ThreadPoolExecutor
. Certains de mes coéquipiers ont dit que la seconde (ThreadPoolExecutor) est la bonne façon d'utiliser.
quelqu'un peut-il clarifier ceci pour moi?
6 réponses
Voici la source de Executors.newFixedThreadPool
:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
Il utilise en interne ThreadPoolExecutor
classe avec la configuration par défaut comme vous pouvez le voir ci-dessus. Maintenant, il y a des scénarios où la configuration par défaut n'est pas appropriée, disons à la place de LinkedBlockingQueue
une file d'attente prioritaire doit être utilisée, etc. Dans de tels cas, l'appelant peut travailler directement sur ThreadPoolExecutor
en l'instanciant et en lui passant la configuration désirée.
alors cela fera une différence?
il va rendre votre code plus compliqué pour peu d'avantage.
j'essaie de comprendre quelle est la différence entre mon code original qui utilise ExecutorService et le nouveau code que j'ai collé qui utilise ThreadPoolExectuor?
à Côté de rien. Executors
crée un ThreadPoolExecutor pour faire le vrai travail.
Certains de mes coéquipiers la deuxième (ThreadPoolExecutor) est la bonne façon d'utiliser?
ce n'est pas parce que c'est plus compliqué que c'est la bonne chose à faire. Les concepteurs ont fourni les exécuteurs.newXxxx méthodes pour rendre la vie plus simple pour vous et parce qu'ils s'attendaient à l'utilisation de ces méthodes. Je vous suggère de les utiliser ainsi.
Executors#newFixedThreadPool (int nThreads)
ExecutorService executor = Executors.newFixedThreadPool(20);
est fondamentalement
return new ThreadPoolExecutor(20, 20,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
2.
BlockingQueue<Runnable> threadPool = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor tpExecutor = new ThreadPoolExecutor(20, 2000, 0L,
TimeUnit.MILLISECONDS, threadPool);
dans le second cas, vous augmentez le maxPoolSize à 2000, ce dont je doute que vous ayez besoin.
je crois un avantage de plus est avec RejectionHandler. Corrigez-moi si mal
après 2 jours de GC out of memory exception
,ThreadPoolExecutor
a sauvé ma vie. :)
comme Balaji l'a dit,
[..] un avantage de plus est avec RejectionHandler.
Dans mon cas, j'ai eu beaucoup de RejectedExecutionException
et en spécifiant (comme suit) la Politique de rejet a résolu tous mes problèmes.
private ThreadPoolExecutor executor = new ThreadPoolExecutor(1, cpus, 1, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardPolicy());
Mais attention! Il ne fonctionne que si vous ne pas besoin d'exécuter les fils que vous soumettez à l'exécuteur.
Pour plus d'informations sur ThreadPoolExecutor
regardez la réponse de Darren
dans le premier exemple, vous avez créé seulement 20 threads avec la déclaration ci-dessous
ExecutorService executor = Executors.newFixedThreadPool(20);
dans le second exemple, vous avez défini la plage des limites de thread entre 20 to 2000
ThreadPoolExecutor tpExecutor = new ThreadPoolExecutor(20, 2000, 0L,
TimeUnit.MILLISECONDS,threadPool);
plus de threads sont disponibles pour le traitement. Mais vous avez configuré la file d'attente des tâches comme file d'attente illimitée.
ThreadPoolExecutor serait plus efficace si vous avez personnalisé beaucoup ou tous les paramètres ci-dessous.
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
RejectedExecutionHandler
serait utile lorsque vous définissez max capacity for workQueue
et le nombre de tâches qui ont été soumises à L'exécuteur sont plus que workQueue
capacité.
consultez la section Tâches rejetées dans ThreadPoolExecutor pour plus de détails.