188 votes

Pourquoi crée un Thread censé être cher ?

La Java des tutoriels dire que la création d'un Thread est cher. Mais pourquoi exactement est-il cher? Exactement ce qui se passe quand un Fil de Java est créé, ce qui rend sa création cher? Je prends la déclaration est vraie, mais je suis seulement intéressé par la mécanique de création de Thread dans la JVM.

Fil du cycle de vie des frais généraux. Création de Thread et de démontage ne sont pas libres. Les frais généraux réels varie entre plates-formes, mais de création de thread prend du temps, de l'introduction de la latence dans le traitement de la demande, et nécessite une certaine activité de traitement par la JVM et les OS. Si les demandes sont fréquentes et léger, comme dans la plupart des applications de serveur, la création d'un nouveau thread pour chaque demande peut consommer d'importantes ressources informatiques.

À partir de Java de la Simultanéité dans la Pratique
Par Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, Doug Lea
Imprimer ISBN-10: 0-321-34960-1

162voto

Stephen C Points 255558

Java création de thread est cher, car il est un peu juste du travail:

  • Un grand bloc de mémoire doit être alloué et initialisé pour la pile de thread.
  • Système d'appels doivent être faits pour créer / enregistrer le natif des threads avec le système d'exploitation hôte.
  • Descripteurs doit être créé, initialisé et ajouté à la JVM des structures de données internes.

Il est également coûteux dans le sens que le fil des liens en bas de ressources, tant qu'il est vivant; par exemple, la pile de thread, tous les objets accessibles à partir de la pile, la JVM fil des descripteurs, l'OS natif des threads de descripteurs.

Toutes ces choses sont de la plate-forme, mais ils ne sont pas pas cher sur toute la plate-forme Java que j'ai jamais rencontré.


Une recherche Google m'a trouvé un vieux de référence qui présente une création de thread taux de ~4000 par seconde sur un Sun Java 1.4.1 sur un millésime 2002 à double processeur Xeon l'exécution de millésime 2002 Linux. Plus moderne de la plateforme donnera de meilleurs chiffres ... et je ne peux pas commenter sur la méthodologie ... mais au moins ça donne une idée de combien coûte la création de threads est susceptible d'être.

Peter Lawrey de l'analyse comparative indique que la création de threads est nettement plus rapide ces jours-ci dans l'absolu, mais il est difficile de savoir comment une grande partie de cela est dû à des améliorations en Java et/ou l'OS ... ou processeur plus rapide des vitesses. Mais ses numéros de toujours indiquer un 150+ pli amélioration si vous utilisez un pool de threads rapport à la création/de commencer un nouveau thread à chaque fois. (Et il fait le point, que tout cela est relatif ...)


(Ci-dessus suppose "threads natifs" plutôt que de "fils verts", mais les machines virtuelles utilisent tous des threads natifs pour des raisons de performances. Fils verts sont peut-être moins cher de créer, mais vous payez pour cela dans d'autres domaines.)


J'ai fait un peu de creuser pour voir comment Java pile du thread devient vraiment affecté. Dans le cas de OpenJDK 6 sur Linux, la pile de thread est alloué par l'appel à l' pthread_create qui crée le thread natif. (La JVM ne passe pas pthread_create un préaffectés de la pile.)

Ensuite, au sein d' pthread_create la pile est attribué par un appel à l' mmap comme suit:

mmap(0, attr.__stacksize, 
     PROT_READ|PROT_WRITE|PROT_EXEC, 
     MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)

Selon man mmap, MAP_ANONYMOUS drapeau causes de la mémoire pour être initialisées à zéro.

Ainsi, même si il pourrait ne pas être essentiel que de nouvelles Java piles de threads sont mis à zéro (par la JVM spec), dans la pratique (au moins avec OpenJDK 6 sur Linux), ils sont remis à zéro.

85voto

Peter Lawrey Points 229686

D'autres ont discuté où les coûts de filetage viennent. Cette réponse couvre pourquoi la création d'un thread n'est pas si cher que ça par rapport à de nombreuses opérations, mais relativement cher par rapport à l'exécution de la tâche des alternatives, qui sont relativement moins chers.

Le plus évident alternative à l'exécution d'une tâche dans un autre thread pour exécuter la tâche dans le même thread. C'est difficile à saisir pour ceux en supposant que plusieurs threads sont toujours mieux. La logique est que si les frais généraux de l'ajout de la tâche à un autre thread est plus grande que le gain de temps, il peut être plus rapide pour effectuer la tâche dans le thread courant.

Une autre alternative est d'utiliser un pool de threads. Un pool de threads peut être plus efficace pour deux raisons. 1) il réutilise les threads déjà créé. 2) vous pouvez régler/contrôler le nombre de threads pour vous garantir des performances optimales.

Le programme suivant imprime....

Time for a task to complete in a new Thread 71.3 us
Time for a task to complete in a thread pool 0.39 us
Time for a task to complete in the same thread 0.08 us
Time for a task to complete in a new Thread 65.4 us
Time for a task to complete in a thread pool 0.37 us
Time for a task to complete in the same thread 0.08 us
Time for a task to complete in a new Thread 61.4 us
Time for a task to complete in a thread pool 0.38 us
Time for a task to complete in the same thread 0.08 us

Ceci est un test pour une tâche triviale qui expose les frais généraux de chaque filetage option. (Cette tâche de test est le genre de tâche qui est en fait le mieux exécuté dans le thread courant.)

final BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
Runnable task = new Runnable() {
    @Override
    public void run() {
        queue.add(1);
    }
};

for (int t = 0; t < 3; t++) {
    {
        long start = System.nanoTime();
        int runs = 20000;
        for (int i = 0; i < runs; i++)
            new Thread(task).start();
        for (int i = 0; i < runs; i++)
            queue.take();
        long time = System.nanoTime() - start;
        System.out.printf("Time for a task to complete in a new Thread %.1f us%n", time / runs / 1000.0);
    }
    {
        int threads = Runtime.getRuntime().availableProcessors();
        ExecutorService es = Executors.newFixedThreadPool(threads);
        long start = System.nanoTime();
        int runs = 200000;
        for (int i = 0; i < runs; i++)
            es.execute(task);
        for (int i = 0; i < runs; i++)
            queue.take();
        long time = System.nanoTime() - start;
        System.out.printf("Time for a task to complete in a thread pool %.2f us%n", time / runs / 1000.0);
        es.shutdown();
    }
    {
        long start = System.nanoTime();
        int runs = 200000;
        for (int i = 0; i < runs; i++)
            task.run();
        for (int i = 0; i < runs; i++)
            queue.take();
        long time = System.nanoTime() - start;
        System.out.printf("Time for a task to complete in the same thread %.2f us%n", time / runs / 1000.0);
    }
}
}

Comme vous pouvez le voir, la création d'un nouveau thread seulement les coûts de ~70 µs. Cela pourrait être considéré comme négligeable dans beaucoup, sinon la plupart, des cas d'utilisation. Relativement parlant, il est plus cher que les solutions de rechange et, pour certaines situations, un pool de threads ou non à l'aide de threads est une meilleure solution.

32voto

Michael Borgwardt Points 181658

En théorie, cela dépend de la JVM. Dans la pratique, chaque thread a une quantité relativement importante de la pile de la mémoire (256 ko par défaut, je pense). En outre, les threads sont mis en œuvre comme OS fils, ce qui leur création implique un OS d'appel, c'est à dire un changement de contexte.

Faire comprendre que "cher" dans le calcul est toujours très relatif. La création de threads est très cher par rapport à la création de la plupart des objets, mais pas très cher par rapport à un hasard disque dur de chercher. Vous n'avez pas à éviter de créer des threads à tout prix, mais de créer des centaines d'entre eux par seconde n'est pas une initiative intelligente. Dans la plupart des cas, si votre conception appels pour beaucoup de threads, vous devez utiliser un taille du pool de threads.

9voto

uʍop ǝpısdn Points 16540

Il existe deux types de threads:

  1. Bon threads: ce sont des abstractions autour de l'exploitation sous-jacent du système d'enfilage des installations. Création de Thread est donc aussi cher que le système est -- il y a toujours un rétroprojecteur.

  2. "Vert" threads: créé et programmé par la JVM, ils sont moins chers, mais pas de la bonne paralellism se produit. Ces comporter comme des threads, mais sont exécutées à l'intérieur de la JVM fil dans l'OS. Ils ne sont pas souvent utilisés, à ma connaissance.

Le facteur le plus important, je pense, dans la création de thread frais généraux, est la pile de la taille que vous avez définis pour votre fils. Pile de Thread-la taille peut être passé en paramètre lors de l'exécution de la machine virtuelle.

Autre que cela, la création de threads est principalement dépendants, et même VM-dépendant de l'implémentation.

Maintenant, permettez-moi de remarquer une chose: la création de threads est cher, si vous prévoyez de tir 2000 threads par seconde, chaque seconde de votre exécution. La JVM n'est pas conçu pour gérer cela. Si vous avez un couple stable de travailleurs qui ne sera pas tiré et tué plus de et plus, se détendre.

5voto

Philip JF Points 17248

Création de Threads nécessite de répartir une bonne quantité de mémoire puisqu’il a à faire non pas un, mais deux nouvelles piles (un pour le code java, pour le code natif). Utilisation des Pools d’exécuteurs/Thread peut éviter les frais généraux, en réutilisant les threads pour des tâches multiples. http://download.Oracle.com/javase/1.5.0/docs/API/Java/util/concurrent/Executor.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X