1. บทนำ
บทความนี้บันทึกคะแนนความรู้บางอย่างเกี่ยวกับกลไกการขัดจังหวะใน Java multithreading ส่วนใหญ่ประกอบด้วยความแตกต่างระหว่างวิธีการหยุดการขัดจังหวะ () และวิธีการ ISINTERRUPTED () และดำเนินการวิเคราะห์อย่างง่ายจากการใช้งานซอร์สโค้ด
มี 3 วิธีในการยุติเธรดการรันใน Java
①เธรดออกปกตินั่นคือวิธีการเรียกใช้ () ได้ถูกดำเนินการ
②ใช้เมธอดหยุด () ในคลาสเธรดเพื่อยุติเธรด อย่างไรก็ตามวิธีการหยุด () หมดอายุแล้วและไม่แนะนำให้ใช้งาน
③ใช้กลไกการขัดจังหวะ
ไม่มีอะไรจะทำเมื่อเธรดออกจากปกติ กลไกการขัดจังหวะมีการแนะนำรายละเอียดด้านล่าง ก่อนอื่นให้ดูที่ซอร์สโค้ดของวิธีการหยุด () กุญแจสำคัญคือความคิดเห็นเกี่ยวกับซอร์สโค้ด มันอธิบายว่าทำไมหยุด () ไม่ปลอดภัยเธรดใดที่หยุดโดยวิธีการหยุด ()
/*** บังคับให้เธรดหยุดการดำเนินการ* <p>* หากมีการติดตั้งตัวจัดการความปลอดภัยให้ใช้วิธี <code> ตรวจสอบ </code>* เมธอดถูกเรียกด้วย <code> </code>* นี่เป็นอาร์กิวเมนต์ สิ่งนี้อาจส่งผลให้ A* <code> SecurityException </code> ได้รับการยก (ในเธรดปัจจุบัน)* <p>* หากเธรดนี้แตกต่างจากเธรดปัจจุบัน (นั่นคือเธรด* ปัจจุบันกำลังพยายามหยุดเธรดนอกเหนือจากตัวเอง) วิธีการนี้ A* <code> SecurityException </code> (ในเธรดปัจจุบัน)* <p>* เธรดที่แสดงโดยเธรดนี้ถูกบังคับให้หยุดสิ่งที่* มันทำผิดปกติและจะโยนวัตถุที่สร้างขึ้นใหม่* <code> threaddeath </code> เป็นข้อยกเว้น* <p>* <code> Threaddeath </code> เว้นแต่จะต้องดำเนินการพิเศษ* การดำเนินการล้างข้อมูล (โปรดทราบว่าการขว้าง* <code> Threaddeath </code> ทำให้ <code> ในที่สุด </code> clauses ของ* <code> ลองใช้คำสั่ง </code> ที่จะดำเนินการก่อนที่เธรด* จะตายอย่างเป็นทางการ) หากคำสั่ง </code> catch </code> จะจับ A* <code> threaddeath </code> วัตถุมันเป็นสิ่งสำคัญที่จะต้องเปลี่ยนวัตถุ* เพื่อให้เธรดตายจริง* <p>* ตัวจัดการข้อผิดพลาดระดับบนสุดที่ตอบสนอง แก้ไขเธรดนี้* @See #Interrupt ()* @See #CheckAccess ()* @See #RUN ()* @SEE #START ()* @See ThreadDeath* @See ThreadGroup #Uncaughtexception การหยุดเธรดด้วย* thread.stop ทำให้มันปลดล็อคจอภาพทั้งหมดว่ามัน* ล็อค (เป็นผลที่ตามมาตามธรรมชาติของข้อยกเว้น* <code> threaddeath </code> ที่ไม่ถูกตรวจสอบ หาก* วัตถุใด ๆ ที่ได้รับการปกป้องก่อนหน้านี้โดยจอภาพเหล่านี้อยู่ในสถานะที่ไม่สอดคล้องกันวัตถุที่เสียหายจะปรากฏให้เห็นถึง* เธรดอื่น ๆ ซึ่งอาจส่งผลให้เกิดพฤติกรรมโดยพลการ การใช้งานจำนวนมากของ <code> หยุด </code> ควรถูกแทนที่ด้วยรหัสที่เพียงแค่แก้ไขตัวแปรบางอย่างเพื่อระบุว่าเธรดเป้าหมายควรหยุดทำงาน เธรดเป้าหมายควรตรวจสอบตัวแปรนี้* เป็นประจำและกลับจากวิธีการเรียกใช้ในแฟชั่นที่เป็นระเบียบ* หากตัวแปรระบุว่าจะหยุดทำงาน หากเธรด* เป้าหมายรอเป็นระยะเวลานาน (บนตัวแปรเงื่อนไข* ตัวอย่างเช่น) ควรใช้วิธี <code> interrupt </code> เพื่อขัดจังหวะการรอ* สำหรับข้อมูลเพิ่มเติมดู* <a href = "{@docroot} /../ technotes/guides/guides/guides เลิกใช้แล้ว? </a>.*/@deprecatedpublic final void stop () {stop (new Threaddeath ());}ดังที่แสดงไว้ข้างต้นบรรทัดที่ 9 ถึง 16 ระบุว่าวิธีการหยุด () สามารถหยุด "เธรดอื่น ๆ " เธรดที่เรียกใช้เมธอด thread.stop () เรียกว่าเธรดปัจจุบันในขณะที่ "เธรดอื่น ๆ " คือเธรดที่แสดงโดยเธรดวัตถุที่เรียกเมธอด thread.stop ()
ชอบ:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {เธรด MyThread = ใหม่ MyThread ... // .... thread.stop (); // .. }ในวิธีหลักเธรดปัจจุบันคือเธรดหลัก มันดำเนินการกับบรรทัด 4 และต้องการหยุดเธรด "เธรดอื่น ๆ " เธรดอื่นนี้เป็นเธรดที่แสดงโดยวัตถุเธรดของคลาส MyThread ใหม่
บรรทัดที่ 21 ถึง 23 ระบุว่าเธรดที่ยังไม่ได้เริ่มต้นยังสามารถหยุดได้ เอฟเฟกต์ของมันคือ: เมื่อเธรดเริ่มต้นมันจะสิ้นสุดลงทันที
ความคิดเห็นหลังจากบรรทัดที่ 48 แสดงให้เห็นอย่างลึกซึ้งว่าทำไมวิธีการหยุด () จึงเลิกใช้แล้ว! ทำไมมันถึงไม่ปลอดภัย
ตัวอย่างเช่นเธรด Threada มีจอภาพที่รับผิดชอบในการปกป้องทรัพยากรที่สำคัญบางอย่างเช่นจำนวนการโอนเงินของธนาคาร เมื่อกระบวนการถ่ายโอนกำลังดำเนินการเธรดหลักจะเรียกเมธอด threada.stop () เป็นผลให้การตรวจสอบถูกปล่อยออกมาและทรัพยากรที่ปกป้อง (จำนวนการถ่ายโอน) มีแนวโน้มที่จะไม่สอดคล้องกัน ตัวอย่างเช่นบัญชี A ลดลง 100 ในขณะที่บัญชี B ไม่เพิ่มขึ้น 100
ประการที่สองกลไกการขัดจังหวะ
มีรายละเอียดมากเกินไปเกี่ยวกับวิธีการใช้กลไกการขัดจังหวะอย่างถูกต้องใน Java ทั้งวิธีการขัดจังหวะ () และ ISINTERRUPTED () สะท้อนให้เห็นว่าเธรดปัจจุบันอยู่ในสถานะขัดจังหวะหรือไม่
①ขัดจังหวะ ()
/*** ทดสอบว่าเธรดปัจจุบันถูกขัดจังหวะหรือไม่ สถานะ* <i> ที่ถูกขัดจังหวะ </i> ของเธรดจะถูกล้างด้วยวิธีนี้ ในคำอื่น ๆ ถ้าวิธีนี้จะถูกเรียกสองครั้งติดต่อกันการโทร* ครั้งที่สองจะส่งคืนเท็จ (เว้นแต่เธรดปัจจุบันจะถูกขัดจังหวะอีกครั้งหลังจากการโทรครั้งแรกได้ล้างสถานะการขัดจังหวะ* และก่อนที่การโทรครั้งที่สองจะตรวจสอบ) ถูกขัดจังหวะ;* <code> false </code> มิฉะนั้น* @See #IsInterrupted ()* @revised.*/บูลีนคงที่สาธารณะขัดจังหวะ () {return currentThread (). isInterrupted (จริง);};จากความคิดเห็นในซอร์สโค้ดจะทดสอบสถานะการขัดจังหวะของเธรดปัจจุบันและวิธีนี้จะล้างสถานะการขัดจังหวะ
②isinterrupted ()
/*** ทดสอบว่าเธรดนี้ถูกขัดจังหวะหรือไม่ สถานะ <i> ถูกขัดจังหวะ* สถานะ </i> ของเธรดไม่ได้รับผลกระทบด้วยวิธีนี้ ** <p> การหยุดชะงักของเธรดเพราะเธรดไม่ได้มีชีวิตอยู่* ในช่วงเวลาของการขัดจังหวะจะถูกสะท้อนโดยวิธีนี้ isinterrupted () {return isinterrupted (false);}ดังที่เห็นได้จากความคิดเห็นของซอร์สโค้ดเมธอด isInterrupted () จะไม่ล้างสถานะการขัดจังหวะ
③ความแตกต่างระหว่างวิธีการขัดจังหวะ () และวิธีการ isinterrupted ()
ดังที่เห็นได้จากซอร์สโค้ดทั้งสองวิธีจะเรียกว่า ISInterrupted (Boolean ClearInterrupted) ยกเว้นว่าหนึ่งที่มีพารามิเตอร์เป็นจริงและอื่น ๆ ที่มีพารามิเตอร์เป็นเท็จ
/*** ทดสอบหากมีการขัดจังหวะเธรดบางอย่าง สถานะที่ถูกขัดจังหวะ* จะถูกรีเซ็ตหรือไม่ขึ้นอยู่กับค่าของ ClearInterrupted ที่ผ่าน* ผ่าน*/บูลีนดั้งเดิมส่วนตัว (บูลีนที่ชัดเจน);
ดังนั้นความแตกต่างแรกคือการล้างบิตอินเตอร์รัปต์และอีกอันหนึ่งไม่ได้ล้างบิตอินเตอร์รัปต์ธง
หลังจากวิเคราะห์ซอร์สโค้ดคุณสามารถเห็นความแตกต่างที่สองในคำสั่ง Return:
บูลีนคงที่สาธารณะขัดจังหวะ () {return currentThread (). isInterrupted (true);}/************************/บูลีนสาธารณะ isinterrupted () {return isinterrupted (เท็จ);};ถูกขัดจังหวะ () ทดสอบสถานะที่ถูกขัดจังหวะของเธรดปัจจุบัน ISInterrupted () ทดสอบเธรดที่แสดงโดยวัตถุที่เรียกวิธีการ หนึ่งคือวิธีการคงที่ (ทดสอบสถานะการขัดจังหวะของเธรดปัจจุบัน) และอีกวิธีหนึ่งเป็นวิธีการอินสแตนซ์ (ทดสอบสถานะการขัดจังหวะของเธรดที่แสดงโดยวัตถุอินสแตนซ์)
ต่อไปนี้เป็นตัวอย่างที่เฉพาะเจาะจงเพื่อชี้แจงความแตกต่างนี้เพิ่มเติม
มีคลาสเธรดที่กำหนดเองดังนี้:
คลาสสาธารณะ MyThread ขยายเธรด {@OverridePublic void run () {super.run (); สำหรับ (int i =; i <; i ++) {system.out.println ("i =" + (i +));}}}}}}}}ก่อนอื่นให้ดูตัวอย่างของวิธีการขัดจังหวะ ():
การเรียกใช้คลาสสาธารณะ {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ลอง {mythread เธรด = ใหม่ mythread (); thread.start (); thread.sleep (); thread.interrupt (); // thread.currentthread (). interrupt (); system.out.println ("หยุด? ="+thread.interrupted (); -บรรทัดที่ 5 เริ่มเธรดเธรดและบรรทัดที่ 6 ทำให้ด้ายหลักนอนหลับเป็นเวลา 1 วินาทีเพื่อให้เธรดมีโอกาสได้รับการดำเนินการ CPU
หลังจากเธรดหลักจะนอนเป็นเวลา 1 วินาทีจะดำเนินการต่อไปยังบรรทัดที่ 7 และขอให้ขัดจังหวะเธรดเธรด
บรรทัดที่ 9 ทดสอบว่าเธรดอยู่ในสถานะขัดจังหวะหรือไม่ มีการทดสอบกระทู้ใดที่นี่? - - คำตอบคือเธรดหลัก เพราะ:
(1) ขัดจังหวะ () ทดสอบสถานะการขัดจังหวะของเธรดปัจจุบัน
(2) เธรดหลักดำเนินการคำสั่งบรรทัดที่ 9 ดังนั้นเธรดหลักคือเธรดปัจจุบัน
ลองดูตัวอย่างของวิธีการ isinterrupted ():
การเรียกใช้คลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ลอง {mythread เธรด = new mythread (); thread.start (); thread.sleep (); thread.interrupt (); system.out.println ("หยุดหรือไม่ ="ในบรรทัดที่ 8 วิธีการ isinterrupted () ที่เรียกโดยวัตถุเธรด ดังนั้นสถานะการขัดจังหวะของเธรดที่แสดงโดยวัตถุเธรดจะถูกทดสอบ ตั้งแต่บรรทัด 7 เธรดหลักขอให้ขัดจังหวะเธรดเธรดผลลัพธ์ในบรรทัดที่ 8 คือ: จริง