Écrivez-le d'abord: la pile de threads devrait être le moyen le plus efficace pour localiser les problèmes non fonctionnels des applications multi-thread, et peut être considérée comme une arme tueuse. Les piles de threads sont les meilleures pour analyser les types de problèmes suivants:
Le système a un processeur trop élevé sans raison.
Le système est suspendu, aucune réponse.
Le système fonctionne de plus en plus lent.
Les goulots d'étranglement des performances (comme l'incapacité à utiliser pleinement le CPU, etc.)
Implume du thread, boucle morte, famine, etc.
Le système échoue en raison de trop de threads (comme l'incapacité de créer des threads, etc.).
Comment interpréter la pile de threads
Comme indiqué dans le programme de code source Java suivant:
package org.ccgogoing.study.stackTrace; / ** * @author: luochong400 * @description: Test Thread * @Date: Create in 07:27 PM 2017/12/08 * / public class MyTest {objet obj1 = new Object (); Objet obj2 = nouveau objet (); public void fun1 () {synchronisé (obj1) {fun2 (); }} public void fun2 () {synchronisé (obj2) {while (true) {// Pour imprimer la pile, l'analyse de la pile de fonction ne quitte pas System.out.print (""); }} public static void main (String [] args) {myTest aa = new myTest (); aa.fun1 (); }}Exécutez le programme dans l'idée, puis appuyez sur la touche Ctrl + Break pour imprimer les informations de pile de threads comme suit:
Full Thread Dump Java Hotspot (TM) 64 bits serveur VM (24,79-b02 Mode mixte): "Thread de service" Daemon Prio = 6 TOT = 0x0000000000000000] Java.lang.threm.state: runnable "C2 compilation Tid = 0x000000000C516000 NID = 0xd390 attendant l'état [0x000000000000000] java.lang.thread.state: Runnable "C2 CompilerThread0" Daemon Prio = 10 Tid = 0x000000000000000] Java.Lang.Stat: 0x00000000000000000] Runnable "Monitor Ctrl-Break" Daemon PRIO = 6 TID = 0x000000000C514000 NID = 0xd148 Runnable [0x000000000caee000] java.lang.thread.state: Runnable sur java.net.socketinputStream.SocketRead0 (méthode native) at Java.net.SocketInputStream.SocketRead0 (Méthode native) AT AT AT Java.net.SocketInputStream.SocketRead0 (Méthode native) AT AT AT Java.net.SocketInputStream. java.net.SocketInputStream.read(SocketInputStream.java:152) at java.net.SocketInputStream.read(SocketInputStream.java:122) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283) at Sun.nio.cs.streamdecoder.implead (streamdecoder.java:325) sur Sun.nio.cs.Streamdecoder.Read (streamdecoder.java:177) - Locked <0x00000000d7858b50> (a java.io.inputStreamReader) ATT java.io.inputStreamReader.read (InputStreamReader.java:184) sur java.io.bufferederader.fill (bufferedeader.java:154) sur java.io.bufferedReader.readline (buffereDeader.java:317) -Lerled <0x0000000d7858b50> (a java.io.inputStreamReader) sur java.io.bufferedeader.readline (buffereDeader.java:382) à com.intellij.rt.execution.application.appmainv2 1.Run (appmainv2.java:64) "attacher l'auditeur" demon prio = 10 tid = 0x0000000000000000004a) NID = 0xd24c Runnable [0x0000000000000000] Java.lang.thread.State: Runnable "Signal Dispatcher" Daemon Prio = 10 Tid = 0x000000000000C1A8800 NID = 0xd200 Waiting on Stack [0x0000000000000000] Java.lang.Thread.state: Runnable "Final" TID = 0x0000000000ACEACE6000 NID = 0xCD74 dans object.wait () [0x000000000c13f000] java.lang.thread.state: Waiting (sur le moniteur d'objet) sur java.lang.object.wait (Méthode native) - java.lang.ref.referenceeue.remove (ReferenceQueue.java:135) - Lockée <0x00000000d7284858> (a java.lang.ref.referenceeue $ Lock) sur java.lang.ref.referenceeue.remeve (Referenceeue.java:151) sur java.lang.ref.finalizer $ finalizerthread.run (finalizer.java:209) "Handler de référence" Daemon Prio = 10 TID = 0x00000000ACE4800 NID = 0xce34 dans object.wait () [0x0000000000BF4F000] Java.lang.thread.state: Waiting (sur l'objet) sur l'objet sur java.lang.object.wait (méthode native) - en attente de <0x00000000d7284470> (a java.lang.ref.reference $ Lock) sur java.lang.object.wait (objet.java:503) sur java.lang.ref.reference $ Reference.run (Reference.java:133) - Moins org.ccgogoing.study.stacktrace.mytest.fun2 (mytest.java:22) - verrouillé <0x00000000d77d50c8> (a java.lang.object) à org.ccgogoing.study.stacktrace.mytest.fun1 (Mytest.java:15) -Leled. <0x00000000d77d50b8> (a java.lang.object) sur org.ccgogoing.study.stacktrace.mytest.main (mytest.java:29) "vm thread" prio = 10 tid = 0x000000000ace1000 nid = 0xd0a8 runnable "gc tâche thread # 0 (parallegc)" PRIO = 6 Tid = 0x00000000000023A4000 NID = 0xd398 Runnable "GC Task Thread # 1 (parallelGC)" prio = 6 tid = 0x00000000023a5800 nid = 0xcc20 runnable "gc task thread # 2 (parallelgcc)" prio = 6 Tid = 0x000000000023a7000 NID = 0xb914 runnable "gc # # # # 33 (ParallelGC)" prio=6 tid=0x00000000023a9000 nid=0xd088 runnable "VM Periodic Task Thread" prio=10 tid=0x000000000c53f000 nid=0xc1b4 waiting on condition JNI global references: 138Heap PSYoungGen total 36864K, used 6376K [0x000000000d7280000, 0x00000000d7280000, 0x0000000d9b800000, 0x000000100000000) Eden Space 31744K, 20% utilisé [0x0000000d7280000, 0x0000000d78ba0d0, 0x0000000d9180000) à partir de l'espace 5120K, 0% utilisé [0x000000000d9680000, 5120K, 0% utilisé [0x000000000d9680000, 5120K, 0% utilisé [0x000000000d9680000, 5120K, 0% utilisé [0x000000000d9680000, 5120K, 0% utilisé [0x000000000d9680000, 5120K, 0% USET [0x000000000D 0x0000000d9680000, 0x0000000d9b80000) à l'espace 5120K, 0% utilisé [0x000000000d9180000, 0x0000000d9180000) Paroldgen Total 83456K, used 0k [0x0000000000000085800000, used 0k [0x000000000000000085800000, 83456k, used 0k [0x000000000000000085800000, 83456K, USED 0k [0x000000000000000085800000, 83456K, USET 0k [0x0000000000000085800000, 83456K, USED 0k [0x0000000000000085800000, 83456K, USK 0x0000000008A980000, 0x0000000D7280000) Espace d'objet 83456K, 0% utilisé [0x00000000085800000, 0x0000000085800000, 0x000000008A980000) PSPERMGEN TOTAL 21504K, USET 33008 0x0000000085800000) object space 21504K, 15% used [0x000000000806000000, 0x0000000080939290, 0x0000000081b000000) object space 21504K, 15% used [0x000000000806000000, 0x00000000080939290, 0x00000000081b000000)
Dans la sortie de pile ci-dessus, nous pouvons voir qu'il existe de nombreux threads d'arrière-plan et threads principaux, parmi lesquels seul le thread principal appartient aux threads utilisateur Java, et les autres sont automatiquement créés par des machines virtuelles. Au cours de notre analyse, nous ne nous soucions que des threads utilisateur.
À partir du fil principal ci-dessus, vous pouvez voir le contexte d'appel du thread actuel de manière très intuitive. La signification d'une certaine couche de l'appel d'un thread est la suivante:
sur mytest.fun1 (mytest.java:15) | | | | | | | | | + ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
De plus, il y a une instruction dans la pile: - verrouillée <0x0000000d77d50b8> (a java.lang.object) indiquant que le thread a déjà un verrou <0x0000000d77d50b8>, et les supports d'angle indiquent l'ID de verrouillage. Ceci est automatiquement généré par le système. Nous avons seulement besoin de savoir que la pile est imprimée à chaque fois, et le même ID signifie le même verrou. La première ligne de chaque pile de thread signifie comme suit:
"main" prio = 1 tid = 0x000000000238e800 nid = 0xc940 runnable [0x00000000027af000] | | | | | | | | | | | | | + --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Le langage d'analyse et l'entité exécutoire est une machine virtuelle Java, les threads de la langue Java s'exécutent avec les threads locaux de la machine virtuelle, et sont en fait les threads locaux exécutant le code de thread Java.
Interprétation des serrures
À en juger par la pile de threads ci-dessus, les informations directes contenues dans la pile de threads sont: le nombre de threads, la pile de méthode appelée par chaque thread et l'état de verrouillage actuel. Le nombre de threads peut être compté directement; La pile de méthode appelée par le thread, du bas en haut, signifie quelle méthode sur quelle classe a été appelée par le thread actuel. Et l'état de verrouillage semble un peu délicat. Les informations liées au verrou sont les suivantes:
Lorsqu'un fil possède un verrou, la pile du fil imprime - verrouillé <0x00000000d77d50c8>
Lorsqu'un thread attend que d'autres threads libèrent le verrou, la pile de threads imprime - l'emprise pour verrouiller <0x00000000d77d50c8>
Lorsqu'un thread possède un verrou, mais exécute la méthode d'attente () du verrou, la pile de threads imprime d'abord verrouillée, puis imprime - l'emprise sur
<0x00000000d77d50c8>
Interprétation de l'état du fil
À l'aide de la pile de threads, de nombreux types de problèmes peuvent être analysés et l'analyse de la consommation de processeur est une partie importante de l'analyse de la pile de threads;
Les threads dans TIMED_WAIT et les états d'attente ne doivent pas consommer CPU. Pour les threads dans Runnable, nous devons juger s'ils consomment du processeur en fonction de la nature du code actuel.
S'il s'agit du code d'opération Java pur, il consomme CPU.
S'il s'agit de réseau IO, il consomme rarement le processeur.
S'il s'agit du code local, vous devez juger en fonction de la nature du code local (la pile de threads locale peut être obtenue via PSTACK et GSTACK). S'il s'agit d'un code d'opération pur, il consomme CPU. S'il est suspendu, il ne consomme pas de processeur. Si c'est IO, il ne consomme pas beaucoup de processeur.
Comment analyser les problèmes avec la pile de threads
Les piles de threads sont très utiles pour positionner les questions des types suivants:
Analyse de l'impasse du thread
Analyse excessive du processeur causée par le code Java
Analyse du cycle violent
Analyse des ressources insuffisantes
Analyse du goulot d'étranglement des performances
Analyse de blocage du thread
Je n'expliquerai pas trop le concept de blocage. Si vous ne comprenez pas, vous pouvez le vérifier en ligne;
L'anneau de verrouillage formé par deux ou plusieurs threads en raison de la dépendance de verrouillage de la boucle forme une véritable blocage, comme suit:
J'ai trouvé un niveau Java Deadlock: ===================================================================================================================================================================================================================================================================== ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. Verrouiller le moniteur 0x0000000000AA9ABC78 (objet 0x000000000d77363e0, un java.lang.object), qui est détenu par "org.ccgogoing.study.stacktrace.deadlock.testThread2" Java Stack Informations pour les filetages répertoriés répertoriés above:================================================================================================== ==========================================================================================================. ==========================================================================================================. ==========================================================================================================. org.ccgogoing.study.stacktrace.deadlock.testthread2.fun (testThread2.java:35) - En attente de verrouillage <0x00000000d77363d0> (a java.lang.object) - Locked <0x00000000d77363e0> (a java.lang.object) sur at org.ccgogoing.study.stacktrace.deadlock.testThread1 ": at org.ccgogoing.study.stacktrace.deadlock.testThread1.fun (testThread1.java:33) - Waiting To Lerroun <0x0000000000d77363e0> (a java.lang.object) - Locked) - Locked) - Locked) - Locked) - <0x00000000d77363d0> (a java.lang.object) sur org.ccgogoing.study.stacktrace.deadlock.testThread1.Run (testthread1.java:20) trouvé 1 impasse.
À partir de la pile imprimée, nous pouvons voir "Found One Java au niveau Java:", c'est-à-dire s'il y a une situation de blocage, la pile donnera directement les résultats de l'analyse de l'impasse.
Lorsqu'un ensemble de threads Java meurt, cela signifie un jeu terminé, ces fils y seront toujours accrochés et ne pourront jamais continuer à fonctionner. Lorsque le thread qui a une impasse exécute les fonctions critiques du système, cette impasse peut entraîner la paralysée de l'ensemble du système. Pour restaurer le système, le temps temporaire et le seul moyen de l'éviter est de redémarrer le système. Ensuite, dépêchez-vous et modifiez le bug qui a provoqué cette impasse.
Remarque: Deux threads ou plus qui sont dans l'impasse ne consomment pas de processeur. Certaines personnes croient que le taux d'utilisation de 100% du CPU est causé par une impasse du fil. Cette déclaration est complètement erronée. La boucle morte et le code dans la boucle sont à forte intensité de processeur, ce qui peut conduire à un taux d'utilisation à 100% du CPU. Les opérations IO telles que les sockets ou les bases de données ne consomment pas beaucoup de processeur.