Schreiben Sie es zuerst: Der Thread-Stapel sollte das effektivste Mittel sein, um nicht funktionale Probleme von Multi-Threaden-Anwendungen zu lokalisieren, und kann als Killerwaffe bezeichnet werden. Thread -Stapel können die folgenden Arten von Problemen am besten analysieren:
Das System hat ohne Grund eine zu hohe CPU.
Das System ist suspendiert, keine Antwort.
Das System läuft langsamer und langsamer.
Leistung Engpässe (z. B. Unfähigkeit, die CPU vollständig zu nutzen usw.)
Faden -Deadlock, tote Schleife, Hunger usw.
Das System schlägt aufgrund zu vieler Threads (z. B. der Unfähigkeit, Threads usw.) auszuführen.
So interpretieren Sie den Thread -Stapel
Wie im folgenden Java -Quellcode -Programm gezeigt:
paket org.ccgogoing.study.stacktrace;/** * @Author: luochong400 * @Description: Test Thread * @Date: Erstellen Sie in 07:27 Uhr 2017/12/08 */Public Class MyTest {Object obj1 = new Object (); Objekt obj2 = neues Objekt (); public void fun1 () {synchronized (obj1) {fun2 (); }} public void fun2 () {synchronized (obj2) {while (true) {// Um den Stack zu drucken, beendet die Funktionsstapelanalyse nicht System.out.print (""); }} public static void main (String [] args) {myTest aa = new myTest (); aa.fun1 (); }}Führen Sie das Programm in Idea aus und drücken Sie dann die Taste zur Strg+ -Break -Taste, um die Thread -Stack -Informationen wie folgt auszudrucken:
Full Thread Dump Java Hotspot (TM) 64-Bit-Server VM (24.79-B02 gemischter Modus): "Service Thread" Daemon Prio = 6 TID = 0x00000000C53B000 NID = 0xca58 Runnable [0x0000000000000000000000] Java.Lang.Thread.Sthread.Stache: stand: stand: runnable: runnable "c2 c2 CompilerThrad1" DAYMAL.LAND.STHEAL = 10.Stache: Runnable: Runnable "c2 CompilerThrad1" DAYMAL.LAND.STHEIT: STREAD: STREIT: RUNNENABLE. TID = 0x000000000C516000 NID = 0xD390 Warten unter Zustand [0x000000000000000] Java.lang.Thread.State: Runnable "C2 CompilerThread0" Daemon Prio = 10 TID = 0x000000000C515000 NID = 0xcbac Waiting Lace in Bedingung [0x00000000000000000 000]] Java.lang.Thread.State: Runnable "Monitor Strg-Break" Dämon Prio = 6 TID = 0x000000000C514000 NID = 0xD148 Runnable [0x000000000Caee000] java.lang.thread.SockeTe: Runnable bei java.net.socketinputSocketinStream.SockeT0 (ärgerig) at java. java.net.socketinputstream.read (socketinputstream.java:152) unter java.net.socketinputstream.read (socketinputstream.java:122) at sun.nio.cs.streamdecoder.readbytes (Streamdecoder.java:283) unter sun.nio.cs.streamdecoder.implread (streamdecoder.java:325) at sun.nio.cs.StreamdeCoder.read (StreamDecoder.java:177) - gesperrt <0x000000d7858b50> (a java.io.iio.inputstreamReader) bei java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.BufferedReader.fill(BufferedReader.java:154) at java.io.BufferedReader.readLine(BufferedReader.java:317) - locked <0x0000000d7858b50> (a java.io.inputStreamReader) bei java.io.bufufferedReader.readline (bufferedReader.java:382) bei com.intellij.rt.execution.application.application.Appmainv2 $ 1.run (AppMainv2.java:64) "Listener" -Deemon "-Daema = 10 × × × $00000000000000000000" adaillieren "Dämonien = Dämonom = Dämonom = Dämonom = Dämonom = Dämonom = Daemon = Dämonom = Dämonom = Dämonom = Dämonom = Dämonom = Dämona Dämoned Daemon. nid=0xd24c runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE"Signal Dispatcher" daemon prio=10 tid=0x0000000000c1a8800 nid=0xd200 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE"Finalizer" daemon prio=8 TID = 0x0000000000ACE6000 NID = 0xCD74 IN -Objekt. Java.lang.Ref.Referencequeue.remove (referencequeue.java:135) - gesperrt <0x00000000d7284858> (a java.lang.ref.referenferencequeue $ lock) bei java.lang.ref.referencequeue.remove (referencequeue.java Java.lang.Ref.Finalizer $ FinalizerThread.run (Finalizer.java:209) "Referenzhandler" Daemon Prio = 10 TID = 0x00000000ACE4800 NID = 0xce34 In Object.wait () [0x000000000000bf4f000] java.lang.lang.ALLang.And.Sthread.Sthread. java.lang.object.wait (native Methode) - Warten auf <0x000000d728470> (a java.lang.ref.Reference $ lock) bei java.lang.object.wait (Object.java:503) at java.lang.ref.referenz $ referenceder.run.run (referenzidler.run.run (referenz.run.run) (referenceder.run.run.run.run (referenz.run) (referenceder.run.run.run.run (referenz.run) (referenced.run.run.run.run.run (referenz.run <0x00000000d7284470> (a java.lang.ref.Reference $ lock) "Haupt" PRIO = 6 TID = 0x00000000238e800 NID = 0xc940 Runnable [0x000000027af000] org.ccgogoing.study.stacktrace.MyTest.fun2(MyTest.java:22) - locked <0x00000000d77d50c8> (a java.lang.Object) at org.ccgogoing.study.stacktrace.MyTest.fun1(MyTest.java:15) - locked <0x00000000d77d50b8> (a java.lang.object) at org.ccgogoing.study.stacktrace.myTest.main (myTest.java:29) "VM Thread" Prio = 10 Tid = 0x000000000ACE1000 NID = 0XD0A8 RUNNABLE ". TID = 0x000000000023A4000 NID = 0xD398 Runnable "GC -Task -Thread#1 (parallelgc)" PRIO = 6 TID = 0x00000000023A5800 NID = 0xcc20 Runnable "GC Task Thread 2 (Parallelgc)" 6 TID = 6 TID = 0x00000000000000000000023A7000 id = 0xBabel = 0x0000000000000000023A7000 id = 0xBabel = 0x0000000000000000023A7000 idl. "GC -Task -Thread#3 (parallelgc)" Prio = 6 TID = 0x00000000023a9000 NID = 0xD088 Runnable "VM Periodenaufgabe -Thread" PRIO = 10 TID = 0x000000000C53F000 NID = 0xc1b4 Warten auf Bedingung JNI Global Referenzen: 138Heap PSIGGEP PSIGGE PSIGGE PSOUGGE PSYNEAPEN PSYNEAPEN. [0x000000000d7280000, 0x00000000d7280000, 0x0000000d9b800000, 0x000000100000000) eden space 31744K, 20% used [0x000000000d7280000, 0x0000000d78ba0d0, 0x0000000d9180000) from space 5120K, 0% used [0x000000000d9680000, 0x0000000d9680000, 0x0000000d9b80000) to space 5120K, 0% used [0x000000000d9180000, 0x0000000d9180000, 0x0000000d9180000, 0x0000000d9680000) ParOldGen total 83456K, used 0K [0x000000000085800000, 0x0000000008a980000, 0x0000000d7280000) Objektraum 83456K, 0% verwendet [0x00000000085800000, 0x0000000085800000, 0x00000000000000000000000000000000000000000000 kmgen 21504K, verwendet 3300K. [X0000000000806000000, 0x000000081B000000, 0x0000000085800000) Objektraum 21504K, 15% verwendet [0x0000000806000000, 0x0000000080939290, 0x000000000000000000000000000000000000000000000000000000. 0x00000000080939290, 0x000000081B000000)
In der obigen Stapelausgabe können wir sehen, dass es viele Hintergrund -Threads und Hauptthreads gibt, von denen nur der Haupt -Thread zu Java -Benutzer -Threads gehört und die anderen automatisch von virtuellen Maschinen erstellt werden. Während unserer Analyse kümmern wir uns nur um die Benutzer -Threads.
Aus dem obigen Haupt -Thread können Sie den aufrufenden Kontext des aktuellen Threads auf sehr intuitive Weise sehen. Die Bedeutung einer bestimmten Schicht des Anrufs eines Threads lautet wie folgt:
bei myTest.fun1 (myTest.java:15) | | | | | | | | | +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Darüber hinaus gibt es eine Anweisung im Stapel:- gesperrt <0x0000000D77D50B8> (ein Java.lang.Object), das angibt, dass der Thread bereits eine Sperre <0x0000000D77D50B8> hat, und die Winkelklammern geben die Sperr-ID an. Dies wird automatisch vom System generiert. Wir müssen nur wissen, dass der Stapel jedes Mal gedruckt ist und dieselbe ID das gleiche Schloss bedeutet. Die erste Zeile jedes Fadenstapels bedeutet wie folgt:
"Main" PRIO = 1 TID = 0x000000000238E800 NID = 0xC940 Runnable [0x00000000027af000] | | | | | | | | | | | | | +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Die Sprache analysieren und die ausführende Entität ist eine java -virtuelle Maschine, die Threads in der Java -Sprache mit den lokalen Threads in der virtuellen Maschine ausgeführt und sind tatsächlich die lokalen Threads, die Java -Thread -Code ausführen.
Interpretation von Schlösser
Nach dem obigen Thread -Stapel zu urteilen, lautet die direkten Informationen im Thread -Stapel: Die Anzahl der Threads, der von jedem Thread aufgerufene Method -Stapel und der aktuelle Sperrstatus. Die Anzahl der Threads kann direkt gezählt werden. Der vom Thread aufgerufene Method -Stapel von unten nach oben bedeutet, welche Methode, auf welcher Klasse der aktuelle Thread aufgerufen wurde. Und der Schlosszustand scheint ein wenig schwierig zu sein. Die Informationen zur Sperre sind wie folgt:
Wenn ein Thread ein Schloss besitzt, druckt der Stapel des Threads -locked <0x00000000D77D50C8>
Wenn ein Faden darauf wartet, dass andere Threads das Sperre veröffentlichen, druckt der Thread -Stapel -erwarten Sie das Sperren <0x00000000D77D50C8>
Wenn ein Thread ein Schloss besitzt, aber die Wait () -Methode des Schlosses ausführt, druckt der Thread -Stapel zuerst gesperrt und dann druckt -und dreht sich an -eingeschaltet.
<0x00000000D77D50C8>
Interpretation des Fadenzustands
Mit Hilfe des Thread -Stacks können viele Arten von Problemen analysiert werden, und die CPU -Verbrauchsanalyse ist ein wichtiger Bestandteil der Thread -Stapel -Analyse.
Themen in Timed_waiting und Wartezustände dürfen keine CPU konsumieren. Bei Threads in Runnable müssen wir beurteilen, ob sie CPU basierend auf der Art des aktuellen Code konsumieren.
Wenn es sich um einen reinen Java -Betriebscode handelt, konsumiert er CPU.
Wenn es sich um Netzwerk -IO handelt, verbraucht es selten die CPU.
Wenn es sich um einen lokalen Code handelt, sollten Sie nach der Art des lokalen Code beurteilen (der lokale Thread -Stapel kann über PStack und GSTACK erhalten werden). Wenn es sich um einen reinen Betriebscode handelt, konsumiert es CPU. Wenn es suspendiert ist, verbraucht es keine CPU. Wenn es sich um IO handelt, verbraucht es nicht viel CPU.
So analysieren Sie Probleme mit dem Thread -Stapel
Thread -Stapel sind sehr hilfreich bei der Positionierung von Fragen der folgenden Typen:
Analyse des Faden -Deadlocks
Übermäßige CPU -Analyse durch Java -Code verursacht
Gewaltzyklusanalyse
Analyse unzureichender Ressourcen
Leistung Engpassanalyse
Faden -Deadlock -Analyse
Ich werde nicht zu viel über das Konzept des Deadlocks erklären. Wenn Sie nicht verstehen, können Sie es online überprüfen.
Der Schlossring, der durch zwei oder mehr Fäden aufgrund der Schließabhängigkeit der Schleife gebildet wird, bildet wie folgt einen echten Deadlock:
Fand einen Java-Level Deadlock: ======================================================================= ====================================================================== ====================================================================== ====================================================================== ====================================================================== ====================================================================== ====================================================================== ====================================================================== Sperrmonitor 0x0000000000A9ABC78 (Objekt 0x000000000d77363e0, A Java.lang.Object), das von "org.ccgogoing above:================================================================================================== ==========================================================ieben ==========================================================ieben ==========================================================ieben org.ccgogoing.study.stacktrace.deadlock.testthread2.fun (testthread2.java:35) - wartet auf Sperrung <0x000000d77363d0> (a Java.lang.Object) - gesperrt <0x00000000000000d7363e0> (a java.object org.ccgogoing.study.stacktrace.deadlock.TestThread1": at org.ccgogoing.study.stacktrace.deadlock.TestThread1.fun(TestThread1.java:33) - waiting to lock <0x00000000d77363e0> (a java.lang.Object) - locked <0x00000000d77363d0> (a java.lang.object) at org.ccgogoing.study.stacktrace.deadlock.testthread1.run (testthread1.java:20) 1 Deadlock gefunden.
Aus dem gedruckten Stapel können wir "einen Java-Level-Deadlock gefunden" gefunden: Das heißt, wenn es eine Deadlock-Situation gibt, liefert der Stapel die Ergebnisse der Deadlock-Analyse direkt.
Wenn ein Satz Java -Threads stirbt, bedeutet es, dass diese Threads immer dort aufgehängt werden und nie in der Lage sein, weiter zu laufen. Wenn der Thread mit einem Deadlock die kritischen Funktionen des Systems ausführt, kann dieser Deadlock dazu führen, dass das gesamte System gelähmt wird. Um das System wiederherzustellen, besteht die vorübergehende und einzige Möglichkeit, das System neu zu starten. Dann beeilen Sie sich und ändern Sie den Fehler, der diesen Deadlock verursacht hat.
HINWEIS: Zwei oder mehr Fäden, die abgestimmt sind, konsumieren keine CPU. Einige Leute glauben, dass die 100% ige Nutzungsrate der CPU durch Thread -Deadlock verursacht wird. Diese Aussage ist völlig falsch. Die tote Schleife und der Code in der Schleife sind CPU-intensiv, was zu einer 100% igen Nutzungsrate der CPU führen kann. IO -Operationen wie Sockets oder Datenbanken verbrauchen nicht viel CPU.