วิธีวิเคราะห์การถ่ายโอนข้อมูลเธรด java


100

ฉันพยายามทำความเข้าใจเพิ่มเติมเกี่ยวกับ java โดยเฉพาะเกี่ยวกับการจัดการหน่วยความจำและเธรด ด้วยเหตุนี้ฉันเพิ่งพบความสนใจในการดูที่ทิ้งเธรด

นี่คือไม่กี่บรรทัดที่นำมาจากเว็บแอปโดยใช้ VisualVM ซึ่งเป็นเครื่องมือในตัวสำหรับ java:

"Finalizer" daemon prio=8 tid=0x02b3d000 nid=0x898 in Object.wait() [0x02d0f000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

   Locked ownable synchronizers:
    - None

"Reference Handler" daemon prio=10 tid=0x02b3b800 nid=0x494 in Object.wait() [0x02cbf000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x27ef0310> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <0x27ef0310> (a java.lang.ref.Reference$Lock)

ก่อนอื่นฉันมีคำถามเกี่ยวกับชื่อตัวแปร:

  • tid and nid แปลว่าอะไร?
  • รูปในวงเล็บเหลี่ยมหลัง Object.wait คืออะไร?

จากนั้นสำหรับสแต็กติดตามตัวเอง:

  • การรอบน<..... > (java.lang .... ) หมายถึงอะไรและตัวเลขใน<.. > คืออะไร
  • มันหมายความว่าอะไรล็อค <..... > (a java.lang .... )คำถามเดียวกันมีอะไรอยู่ใน<.. >

ฉันคิดว่าคำว่าล็อคเกี่ยวข้องกับเงื่อนไขการรอสักครั้ง แต่ฉันคิดผิด อันที่จริงฉันสงสัยว่าทำไมล็อกซ้ำสามครั้ง แต่เธรดอยู่ในสถานะรันได้ดังที่เห็นในดัมพ์เดียวกัน:

"Thread-0" prio=6 tid=0x02ee3800 nid=0xc1c runnable [0x03eaf000]
   java.lang.Thread.State: RUNNABLE
    at java.io.FileInputStream.readBytes(Native Method)
    at java.io.FileInputStream.read(FileInputStream.java:199)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
    - locked <0x23963378> (a java.io.BufferedInputStream)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
    - locked <0x23968450> (a java.io.InputStreamReader)
    at java.io.InputStreamReader.read(InputStreamReader.java:167)
    at java.io.BufferedReader.fill(BufferedReader.java:136)
    at java.io.BufferedReader.readLine(BufferedReader.java:299)
    - locked <0x23968450> (a java.io.InputStreamReader)
    at java.io.BufferedReader.readLine(BufferedReader.java:362)
    at org.codehaus.plexus.util.cli.StreamPumper.run(StreamPumper.java:145)

สุดท้ายนี้เป็นสิ่งที่เลวร้ายที่สุด:

"CompilerThread0" daemon prio=10 tid=0x02b81000 nid=0x698 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

เธรดนี้อยู่ในสถานะรันได้ แต่กำลังรอตามเงื่อนไข เงื่อนไขอะไรและ 0x00000 คืออะไร?

เหตุใดการติดตามสแต็กจึงสั้นโดยไม่มีหลักฐานเกี่ยวกับคลาสเธรด

หากคุณสามารถตอบคำถามทั้งหมดของฉันได้ฉันจะขอบคุณมาก

ขอบคุณ

คำตอบ:


113

TID คือรหัสแอดและ NID คือ: Native thread ID ID นี้ขึ้นอยู่กับแพลตฟอร์มเป็นอย่างมาก มันคือ NID ใน jstack thread ทิ้ง ใน Windows เป็นเพียง ID เธรดระดับ OS ภายในกระบวนการ บน Linux และ Solaris เป็น PID ของเธรด (ซึ่งจะเป็นกระบวนการที่มีน้ำหนักเบา) ใน Mac OS X กล่าวว่าเป็นค่า pthread_t ดั้งเดิม

ไปที่ลิงค์นี้: รหัสเธรดระดับ Java : สำหรับคำจำกัดความและคำอธิบายเพิ่มเติมของสองคำนี้

บนเว็บไซต์ของไอบีเอ็มที่ฉันพบลิงค์นี้: วิธีการแปลความหมายของการถ่ายโอนข้อมูลด้าย ที่ครอบคลุมในรายละเอียดเพิ่มเติม:

มันอธิบายถึงความหมายของการรอคอย: การล็อกป้องกันไม่ให้เอนทิตีมากกว่าหนึ่งเข้าถึงทรัพยากรที่แชร์ แต่ละอ็อบเจ็กต์ใน Java ™มีการล็อกที่เกี่ยวข้อง (ได้มาจากการใช้บล็อกหรือวิธีการซิงโครไนซ์) ในกรณีของ JVM เธรดจะแข่งขันกันเพื่อแย่งชิงทรัพยากรต่างๆใน JVM และล็อกอ็อบเจ็กต์ Java

จากนั้นจะอธิบายว่าจอภาพเป็นกลไกการล็อกชนิดพิเศษที่ใช้ใน JVM เพื่อให้สามารถซิงโครไนซ์ระหว่างเธรดได้อย่างยืดหยุ่น สำหรับจุดประสงค์ของส่วนนี้โปรดอ่านข้อกำหนดในการตรวจสอบและล็อกสลับกัน

จากนั้นจะดำเนินต่อไป:

เพื่อหลีกเลี่ยงการมีมอนิเตอร์บนทุกออบเจ็กต์ JVM มักใช้แฟล็กในคลาสหรือบล็อกเมธอดเพื่อระบุว่าไอเท็มถูกล็อค โดยส่วนใหญ่รหัสจะส่งผ่านส่วนที่ถูกล็อกบางส่วนโดยไม่มีข้อโต้แย้ง ดังนั้นธงผู้พิทักษ์จึงเพียงพอที่จะปกป้องชิ้นส่วนของรหัสนี้ สิ่งนี้เรียกว่าจอภาพแบน อย่างไรก็ตามหากเธรดอื่นต้องการเข้าถึงรหัสบางอย่างที่ถูกล็อกการโต้แย้งของแท้ก็เกิดขึ้น ตอนนี้ JVM ต้องสร้าง (หรือขยาย) อ็อบเจ็กต์มอนิเตอร์เพื่อเก็บเธรดที่สองและจัดให้มีกลไกการส่งสัญญาณเพื่อประสานการเข้าถึงส่วนโค้ด ปัจจุบันจอภาพนี้เรียกว่าจอภาพที่สูงเกินจริง

นี่คือคำอธิบายเชิงลึกเพิ่มเติมเกี่ยวกับสิ่งที่คุณเห็นบนบรรทัดจากการถ่ายโอนข้อมูลเธรด เธรด Java ถูกใช้งานโดยเธรดเนทีฟของระบบปฏิบัติการ แต่ละเธรดแสดงด้วยเส้นเป็นตัวหนาเช่น:

"เธรด -1" (TID: 0x9017A0, sys_thread_t: 0x23EAC8, สถานะ: R, ID ดั้งเดิม: 0x6E4) prio = 5

* 6 รายการต่อไปนี้จะอธิบายสิ่งนี้เนื่องจากฉันได้จับคู่จากตัวอย่างค่าในวงเล็บ []:

  1. ชื่อ [ Thread-1 ]
  2. ตัวระบุ [ 0x9017A0 ]
  3. ที่อยู่โครงสร้างข้อมูล JVM [ 0x23EAC8 ],
  4. สถานะปัจจุบัน [ R ]
  5. ตัวระบุเธรดเนทีฟ [ 0x6E4 ]
  6. และลำดับความสำคัญ [ 5 ]

"wait on" ดูเหมือนจะเป็นเธรด daemon ที่เชื่อมโยงกับ jvm เองไม่ใช่เธรดแอ็พพลิเคชัน perse เมื่อคุณได้รับ "ใน Object.wait ()" นั่นหมายถึงเธรด daemon "finalizer" ที่นี่กำลังรอการแจ้งเตือนเกี่ยวกับการล็อกวัตถุในกรณีนี้จะแสดงให้คุณเห็นว่ากำลังรอการแจ้งเตือนใดอยู่: "- กำลังรอ <0x27ef0288> (a java.lang.ref.ReferenceQueue $ Lock) "

คำจำกัดความของ ReferenceQueue คือคิวอ้างอิงซึ่งอ็อบเจ็กต์อ้างอิงที่ลงทะเบียนถูกต่อท้ายโดยตัวรวบรวมขยะหลังจากตรวจพบการเปลี่ยนแปลงความสามารถในการเข้าถึงที่เหมาะสม

เธรด Finalizer รันดังนั้นการรวบรวมขยะจึงดำเนินการเพื่อล้างทรัพยากรที่เกี่ยวข้องกับอ็อบเจ็กต์ ถ้าฉันเห็นว่ามันเป็นจริงโปรแกรมสุดท้ายจะไม่สามารถล็อควัตถุนี้ได้: java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:118) เนื่องจากวัตถุ java กำลังเรียกใช้เมธอดดังนั้น finalizer thread คือ ล็อคจนกว่าวัตถุนั้นจะเสร็จสิ้นด้วยงานปัจจุบัน

นอกจากนี้ Finalizer ไม่ได้ต้องการเพียงแค่เรียกคืนหน่วยความจำเท่านั้น แต่ยังเกี่ยวข้องกับการล้างทรัพยากรอีกด้วย ฉันต้องทำการศึกษาเพิ่มเติมเกี่ยวกับเรื่องนี้ แต่ถ้าคุณมีไฟล์ที่เปิดอยู่ซ็อกเก็ตและอื่น ๆ ... ที่เกี่ยวข้องกับเมธอดอ็อบเจ็กต์ตัวสุดท้ายก็จะดำเนินการเพื่อปลดปล่อยไอเท็มเหล่านั้นเช่นกัน

รูปในวงเล็บกำลังสองหลัง Object.wait ในเธรดดัมพ์คืออะไร

เป็นตัวชี้ในหน่วยความจำไปยังเธรด นี่คือคำอธิบายโดยละเอียดเพิ่มเติม:

C.4.1 ข้อมูลด้าย

ส่วนแรกของส่วนเธรดแสดงเธรดที่กระตุ้นให้เกิดข้อผิดพลาดร้ายแรงดังนี้:

Current thread (0x0805ac88):  JavaThread "main" [_thread_in_native, id=21139]
                    |             |         |            |          +-- ID
                    |             |         |            +------------- state
                    |             |         +-------------------------- name
                    |             +------------------------------------ type
                    +-------------------------------------------------- pointer

ตัวชี้เธรดเป็นตัวชี้ไปยังโครงสร้างเธรดภายใน Java VM โดยทั่วไปจะไม่มีผลประโยชน์ใด ๆ เว้นแต่คุณจะทำการดีบัก Java VM หรือไฟล์หลักที่ใช้งานอยู่

คำอธิบายสุดท้ายนี้มาจาก: Troubleshooting Guide for Java SE 6 with HotSpot VM

ต่อไปนี้เป็นลิงก์เพิ่มเติมบางส่วนเกี่ยวกับการทิ้งเธรด


11

เพิ่มเติมจากคำตอบที่ยอดเยี่ยมของ @James Drinkard:

โปรดทราบว่าขึ้นอยู่กับการดำเนินงานพื้นฐานที่java.lang.Thread.Stateของด้ายที่ถูกบล็อกในวิธีพื้นเมืองอาจมีการรายงานเป็นRUNNABLEที่A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

ปรากฎว่าคำอธิบายนี้ยังครอบคลุมถึงการถูกบล็อกในการเรียกระบบปฏิบัติการเช่นการสำรวจความคิดเห็นหรือการดำเนินการอ่านซึ่งน่าจะเป็นเพราะไม่มีการรับประกันว่า JVM สามารถทราบได้เมื่อมีการบล็อกการเรียกใช้เมธอดดั้งเดิมที่ระดับ OS

การอภิปรายจำนวนมากเกี่ยวกับการทิ้งเธรด JVM ที่ฉันเคยเห็นว่าเพิกเฉยต่อความเป็นไปได้นี้โดยสิ้นเชิงหรือมองข้ามความเป็นไปได้โดยไม่คำนึงถึงผลกระทบ - อย่างน้อยก็คือเครื่องมือตรวจสอบอาจรายงานอย่างสับสนว่าเธรดดังกล่าวหลายเธรดกำลัง 'ทำงานอยู่' และยิ่งไปกว่านั้น พวกเขาทั้งหมดทำงานที่ 100%

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.