เมื่อวันศุกร์และสุดสัปดาห์ที่แล้ว ฉันหยุดพักจากงานยุ่งและตรวจสอบการใช้งาน Thread.interrupt และ LockSupport หลังจาก Java 5 ในขณะที่รับชม java cocurrent
ก่อนที่จะแนะนำฉันขอถามคำถามสองสามข้อก่อน
ความสัมพันธ์ระหว่างเมธอด Thread.interrupt() และ InterruptedException คืออะไร ข้อยกเว้น InterruptedException ถูกทริกเกอร์โดยการขัดจังหวะหรือไม่
Thread.interrupt() จะขัดจังหวะการทำงานของเธรดในสถานะใด วิ่งหรือบล็อก?
การเขียนโปรแกรม Thread ทั่วไปจำเป็นต้องให้ความสนใจกับการขัดจังหวะหรือไม่? วิธีจัดการกับมันโดยทั่วไป? มันใช้ทำอะไรได้บ้าง?
อะไรคือความแตกต่างระหว่าง LockSupport.park() และ unpark() และ object.wait() และ notify()?
การใช้วัตถุตัวบล็อกที่ส่งผ่านโดย LockSupport.park (ตัวบล็อกวัตถุ) คืออะไร?
LockSupport สามารถตอบสนองต่อเหตุการณ์ Thread.interrupt () ได้หรือไม่ InterruptedException จะถูกโยนทิ้งหรือไม่
มีฟังก์ชันการโทรกลับที่เกี่ยวข้องสำหรับการประมวลผล Thread.interrupt() หรือไม่ บางอย่างเช่นการโทรขอ?
หากคุณสามารถตอบทุกอย่างชัดเจน นั่นหมายความว่าคุณเข้าใจ Thread.interrupt อย่างถ่องแท้แล้ว และคุณไม่จำเป็นต้องอ่านเพิ่มเติม
หากคุณยังคงไม่ชัดเจน เรามาทำความเข้าใจกับคำถามเหล่านี้กันดีกว่า
มีหลายวิธีในการจัดการกับการขัดจังหวะของเธรด:
โมฆะสาธารณะขัดจังหวะ (): ดำเนินการเหตุการณ์ขัดจังหวะเธรด
public boolean isInterrupted() : ตรวจสอบว่าเธรดปัจจุบันถูกขัดจังหวะหรือไม่
บูลีนคงที่สาธารณะขัดจังหวะ (): ตรวจสอบว่าเธรดปัจจุบันถูกขัดจังหวะหรือไม่และรีเซ็ตข้อมูลขัดจังหวะ แอปที่คล้ายกับ ResetAndGet()
เข้าใจ:
1. แต่ละเธรดมีแฟล็กสถานะขัดจังหวะเพื่อระบุว่าเธรดปัจจุบันอยู่ในสถานะขัดจังหวะหรือไม่
2. โดยทั่วไป มีวิธีการประมวลผลสองวิธีเมื่อเรียกใช้ Thread.interrupt() เมื่อพบสถานะบล็อกที่มีลำดับความสำคัญต่ำ เช่น object.wait(), object.sleep(), object.join() มันจะทริกเกอร์การปลดบล็อกทันทีเพื่อปลดบล็อกและโยน InterruptedException
ในกรณีอื่นๆ Thread.interrupt() จะอัพเดตเฉพาะสถานะสถานะเท่านั้น จากนั้นเธรดผู้ปฏิบัติงานของคุณจะตรวจสอบผ่าน Thread.isInterrrupted() และสามารถดำเนินการประมวลผลที่เกี่ยวข้องได้ เช่น การโยน InterruptedException หรือการล้างสถานะ การยกเลิกงาน เป็นต้น
อธิบายไว้ในอินเทอร์รัปต์ javadoc:
แนวทางปฏิบัติที่ดีที่สุด
มีบทความเกี่ยวกับ IBM ที่ค่อนข้างดี ทฤษฎีและการปฏิบัติของ Java: การจัดการกับ InterruptedException ซึ่งกล่าวถึงแนวทางปฏิบัติที่ดีที่สุดหลายประการสำหรับการจัดการการขัดจังหวะ
อย่ากลืนการขัดจังหวะ (อย่ากิน Interrupt โดยทั่วไปมีการประมวลผลสองประเภท: โยน InterruptedException ต่อไป อีกวิธีหนึ่งคือตั้งค่าสถานะข้อยกเว้น Thread.interupt() ต่อไป เพื่อให้ระดับที่สูงกว่าสามารถจัดการได้ตามลำดับ
คัดลอกรหัสรหัส ดังต่อไปนี้:
TaskRunner คลาสสาธารณะใช้งาน Runnable {
คิว BlockingQueue <งาน> ส่วนตัว;
TaskRunner สาธารณะ (BlockingQueue <Task> คิว) {
this.queue = คิว;
-
โมฆะสาธารณะวิ่ง () {
พยายาม {
ในขณะที่ (จริง) {
งานงาน = Queue.take (10, TimeUnit.SECONDS);
งาน.ดำเนินการ();
-
-
จับ (InterruptedException e) {
// คืนค่าสถานะที่ถูกขัดจังหวะ
Thread.currentThread().ขัดจังหวะ();
-
-
-
คัดลอกรหัสรหัส ดังต่อไปนี้:
TaskRunner คลาสสาธารณะใช้งาน Runnable {
คิว BlockingQueue <งาน> ส่วนตัว;
TaskRunner สาธารณะ (BlockingQueue <Task> คิว) {
this.queue = คิว;
-
โมฆะสาธารณะวิ่ง () {
พยายาม {
ในขณะที่ (จริง) {
งานงาน = Queue.take (10, TimeUnit.SECONDS);
งาน.ดำเนินการ();
-
-
จับ (InterruptedException e) {
// คืนค่าสถานะที่ถูกขัดจังหวะ
Thread.currentThread().ขัดจังหวะ();
-
-
-
การใช้งานที่ยกเลิกได้ด้วย Interrupt (ใช้ Thread.interrupt() เพื่อออกแบบและสนับสนุนงานที่สามารถยกเลิกได้)
คัดลอกรหัสรหัส ดังต่อไปนี้:
PrimeProducer คลาสสาธารณะขยายเธรด {
คิว BlockingQueue <BigInteger> ส่วนตัวสุดท้าย;
PrimeProducer (คิว BlockingQueue <BigInteger>) {
this.queue = คิว;
-
โมฆะสาธารณะวิ่ง () {
พยายาม {
BigInteger p = BigInteger.ONE;
ในขณะที่ (!Thread.currentThread().isInterrupted())
Queue.put(p = p.nextProbablePrime());
} catch (ใช้ InterruptedException) {
/* อนุญาตให้เธรดออก */
-
-
ยกเลิกโมฆะสาธารณะ () { ขัดจังหวะ (); } // เริ่มต้นการขัดจังหวะ
<SPAN style="WHITE-SPACE: ปกติ"> </SPAN>
คัดลอกรหัสรหัส ดังต่อไปนี้:
PrimeProducer คลาสสาธารณะขยายเธรด {
คิว BlockingQueue <BigInteger> ส่วนตัวสุดท้าย;
PrimeProducer (คิว BlockingQueue <BigInteger>) {
this.queue = คิว;
-
โมฆะสาธารณะวิ่ง () {
พยายาม {
BigInteger p = BigInteger.ONE;
ในขณะที่ (!Thread.currentThread().isInterrupted())
Queue.put(p = p.nextProbablePrime());
} catch (ใช้ InterruptedException) {
/* อนุญาตให้เธรดออก */
-
-
ยกเลิกโมฆะสาธารณะ () { ขัดจังหวะ (); } // เริ่มต้นการขัดจังหวะ
<SPAN style="WHITE-SPACE: ปกติ"> </SPAN>
ลงทะเบียนเหตุการณ์การประมวลผลขัดจังหวะ (การใช้งานที่ผิดปกติ)
โดยทั่วไป งานปกติได้รับการออกแบบมาเพื่อจัดการกับการยกเลิก และทั้งหมดจะใช้การโพลที่ใช้งานอยู่เพื่อตรวจสอบ Thread.isInterrupt() ซึ่งมีความฝังตัวอยู่ในธุรกิจในระดับหนึ่ง และยังมีความล่าช้าอีกด้วย คุณต้องรอจนกว่าจะถึงงานถัดไป จุดตรวจ (ใครจะรู้ว่าจุดตรวจถัดไปคือเมื่อใด โดยเฉพาะอย่างยิ่งเมื่อดำเนินการ socket.read ฉันพบปัญหาการหมดเวลาของ HttpClient)
มาดูกันดีกว่า การใช้งาน InterruptedException นั้นมีพื้นฐานมาจากการออกแบบ InterruptibleChannel ซึ่งค่อนข้างฉลาด
คัดลอกรหัสรหัส ดังต่อไปนี้:
interface InterruptAble { // กำหนดอินเทอร์เฟซที่สามารถขัดจังหวะได้
โมฆะสาธารณะขัดจังหวะ () พ่น InterruptedException;
-
คลาสนามธรรม InterruptSupport ใช้ InterruptAble {
บูลีนระเหยส่วนตัวถูกขัดจังหวะ = false;
ผู้ขัดขวางขัดจังหวะส่วนตัว = ใหม่ขัดจังหวะ () {
โมฆะสาธารณะขัดจังหวะ () {
ขัดจังหวะ = จริง;
InterruptSupport.this.interrupt(); // ตำแหน่ง 3
-
-
การดำเนินการบูลีนขั้นสุดท้ายสาธารณะ () พ่น InterruptedException {
พยายาม {
blockedOn(ผู้ขัดขวาง); // ตำแหน่ง 1
if (Thread.currentThread().isInterrupted()) { // ถูกขัดจังหวะทันที
ผู้ขัดขวาง.ขัดจังหวะ();
-
// ดำเนินการรหัสธุรกิจ
ธุรกิจ();
} ในที่สุด {
blockedOn(null); // ตำแหน่ง 2
-
กลับถูกขัดจังหวะ;
-
ธุรกิจโมฆะนามธรรมสาธารณะ () ;
โมฆะนามธรรมสาธารณะขัดจังหวะ ();
// -- sun.misc.SharedSecrets --
โมฆะคงที่ blockedOn (intr ขัดจังหวะ) { // package-private
sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
-
-
คัดลอกรหัสรหัส ดังต่อไปนี้:
interface InterruptAble { // กำหนดอินเทอร์เฟซที่สามารถขัดจังหวะได้
โมฆะสาธารณะขัดจังหวะ () พ่น InterruptedException;
-
คลาสนามธรรม InterruptSupport ใช้ InterruptAble {
บูลีนระเหยส่วนตัวถูกขัดจังหวะ = false;
ผู้ขัดขวางขัดจังหวะส่วนตัว = ใหม่ขัดจังหวะ () {
โมฆะสาธารณะขัดจังหวะ () {
ขัดจังหวะ = จริง;
InterruptSupport.this.interrupt(); // ตำแหน่ง 3
-
-
การดำเนินการบูลีนขั้นสุดท้ายสาธารณะ () พ่น InterruptedException {
พยายาม {
blockedOn(ผู้ขัดขวาง); // ตำแหน่ง 1
if (Thread.currentThread().isInterrupted()) { // ถูกขัดจังหวะทันที
ผู้ขัดขวาง.ขัดจังหวะ();
-
// ดำเนินการรหัสธุรกิจ
ธุรกิจ();
} ในที่สุด {
blockedOn(null); // ตำแหน่ง 2
-
กลับถูกขัดจังหวะ;
-
ธุรกิจโมฆะนามธรรมสาธารณะ () ;
โมฆะนามธรรมสาธารณะขัดจังหวะ ();
// -- sun.misc.SharedSecrets --
โมฆะคงที่ blockedOn (intr ขัดจังหวะ) { // package-private
sun.misc.SharedSecrets.getJavaLangAccess().blockedOn(Thread.currentThread(), intr);
-
-
คำอธิบายรหัสเคล็ดลับบางประการ:
ตำแหน่งที่ 1: ใช้เมธอด blockedOn ที่ sun จัดเตรียมไว้เพื่อผูก hook การประมวลผลเหตุการณ์ขัดจังหวะที่สอดคล้องกันกับเธรดที่ระบุ
ตำแหน่งที่ 2: หลังจากรันโค้ดแล้ว ให้เคลียร์ hook หลีกเลี่ยงผลกระทบต่อเหตุการณ์การประมวลผลเธรดถัดไปเมื่อใช้พูลการเชื่อมต่อ
ตำแหน่งที่ 3: กำหนดวิธีการประมวลผลของฮุกเหตุการณ์ขัดจังหวะและเรียกกลับเมธอด InterruptSupport.this.interrupt() คลาสย่อยสามารถรวมและใช้ตรรกะทางธุรกิจของตนเองได้ เช่น การปิดสตรีมถุงเท้า เป็นต้น
ใช้:
คัดลอกรหัสรหัส ดังต่อไปนี้:
คลาส InterruptRead ขยาย InterruptSupport {
FileInputStream ส่วนตัวใน;
@แทนที่
ธุรกิจโมฆะสาธารณะ () {
File file = new File("/dev/urandom"); // อ่าน linux black hole อย่าอ่านจบ
พยายาม {
ใน = FileInputStream ใหม่ (ไฟล์);
ไบต์ [] ไบต์ = ไบต์ใหม่ [1024];
ในขณะที่ (in.read(ไบต์, 0, 1024) > 0) {
// Thread.sleep (100);
// if (Thread.interrupted()) {// วิธีการตรวจสอบการขัดจังหวะก่อนหน้า
// โยน InterruptedException ใหม่ ("");
-
-
} จับ (ข้อยกเว้นจ) {
โยน RuntimeException ใหม่ (e);
-
-
FileInputStream สาธารณะ getIn () {
กลับเข้ามา;
-
@แทนที่
โมฆะสาธารณะขัดจังหวะ () {
พยายาม {
in.getChannel().ปิด();
} จับ (IOException จ) {
e.printStackTrace();
-
-
-
โมฆะคงที่สาธารณะ main (String args []) พ่นข้อยกเว้น {
การทดสอบ InterruptRead สุดท้าย = new InterruptRead();
เธรด t = เธรดใหม่ () {
@แทนที่
โมฆะสาธารณะวิ่ง () {
เริ่มต้นนาน = System.currentTimeMillis();
พยายาม {
System.out.println("เริ่มอ่านขัดจังหวะ!");
ทดสอบ.ดำเนินการ();
} จับ (InterruptedException e) {
System.out.println("InterruptRead end! cost time : " + (System.currentTimeMillis() - start));
e.printStackTrace();
-
-
-
t.เริ่มต้น();
// ให้ Read ดำเนินการเป็นเวลา 3 วินาทีก่อน
เธรด.สลีป(3000);
//ออกอินเตอร์รัปต์
t.ขัดจังหวะ();
-
คัดลอกรหัสรหัส ดังต่อไปนี้:
คลาส InterruptRead ขยาย InterruptSupport {
FileInputStream ส่วนตัวใน;
@แทนที่
ธุรกิจโมฆะสาธารณะ () {
File file = new File("/dev/urandom"); // อ่าน linux black hole อย่าอ่านจบ
พยายาม {
ใน = FileInputStream ใหม่ (ไฟล์);
ไบต์ [] ไบต์ = ไบต์ใหม่ [1024];
ในขณะที่ (in.read(ไบต์, 0, 1024) > 0) {
// Thread.sleep (100);
// if (Thread.interrupted()) {// วิธีการตรวจสอบการขัดจังหวะก่อนหน้า
// โยน InterruptedException ใหม่ ("");
-
-
} จับ (ข้อยกเว้นจ) {
โยน RuntimeException ใหม่ (e);
-
-
FileInputStream สาธารณะ getIn () {
กลับเข้ามา;
-
@แทนที่
โมฆะสาธารณะขัดจังหวะ () {
พยายาม {
in.getChannel().ปิด();
} จับ (IOException จ) {
e.printStackTrace();
-
-
-
โมฆะคงที่สาธารณะ main (String args []) พ่นข้อยกเว้น {
การทดสอบ InterruptRead สุดท้าย = new InterruptRead();
เธรด t = เธรดใหม่ () {
@แทนที่
โมฆะสาธารณะวิ่ง () {
เริ่มต้นนาน = System.currentTimeMillis();
พยายาม {
System.out.println("เริ่มอ่านขัดจังหวะ!");
ทดสอบ.ดำเนินการ();
} จับ (InterruptedException e) {
System.out.println("InterruptRead end! cost time : " + (System.currentTimeMillis() - start));
e.printStackTrace();
-
-
-
t.เริ่มต้น();
// ให้ Read ดำเนินการเป็นเวลา 3 วินาทีก่อน
เธรด.สลีป(3000);
//ออกอินเตอร์รัปต์
t.ขัดจังหวะ();
-
การแนะนำซอร์สโค้ด jdk:
1. ตะขอที่ซันจัดเตรียมไว้ให้สามารถดูรหัสที่เกี่ยวข้องของระบบบรรทัด: 1125
คัดลอกรหัสรหัส ดังต่อไปนี้:
sun.misc.SharedSecrets.setJavaLangAccess(ใหม่ sun.misc.JavaLangAccess(){
sun.reflect.ConstantPool สาธารณะ getConstantPool (คลาสคลาส) {
กลับ klass.getConstantPool();
-
โมฆะสาธารณะ setAnnotationType (คลาสคลาส, ประเภท AnnotationType) {
klass.setAnnotationType(ชนิด);
-
AnnotationType สาธารณะ getAnnotationType (คลาสคลาส) {
กลับ klass.getAnnotationType();
-
สาธารณะ <E ขยาย Enum <E>>
E [] getEnumConstantsShared (คลาส <E> คลาส) {
กลับ klass.getEnumConstantsShared();
-
โมฆะสาธารณะที่ถูกบล็อก (เธรด t, ขัดจังหวะ b) {
t.blockedOn(b);
-
-
คัดลอกรหัสรหัส ดังต่อไปนี้:
sun.misc.SharedSecrets.setJavaLangAccess(ใหม่ sun.misc.JavaLangAccess(){
sun.reflect.ConstantPool สาธารณะ getConstantPool (คลาสคลาส) {
กลับ klass.getConstantPool();
-
โมฆะสาธารณะ setAnnotationType (คลาสคลาส, ประเภท AnnotationType) {
klass.setAnnotationType(ชนิด);
-
AnnotationType สาธารณะ getAnnotationType (คลาสคลาส) {
กลับ klass.getAnnotationType();
-
สาธารณะ <E ขยาย Enum <E>>
E [] getEnumConstantsShared (คลาส <E> คลาส) {
กลับ klass.getEnumConstantsShared();
-
โมฆะสาธารณะที่ถูกบล็อก (เธรด t, ขัดจังหวะ b) {
t.blockedOn(b);
-
-
2. Thread.ขัดจังหวะ()
คัดลอกรหัสรหัส ดังต่อไปนี้:
โมฆะสาธารณะขัดจังหวะ () {
ถ้า (นี่ != Thread.currentThread())
ตรวจสอบการเข้าถึง();
ซิงโครไนซ์ (blockerLock) {
ขัดจังหวะ b = ตัวบล็อก;
ถ้า (ข != โมฆะ) {
Interrupt0(); // เพียงเพื่อตั้งค่าสถานะขัดจังหวะ
b.interrupt(); //เรียกกลับ
กลับ;
-
-
ขัดจังหวะ0();
-
คัดลอกรหัสรหัส ดังต่อไปนี้:
โมฆะสาธารณะขัดจังหวะ () {
ถ้า (นี่ != Thread.currentThread())
ตรวจสอบการเข้าถึง();
ซิงโครไนซ์ (blockerLock) {
ขัดจังหวะ b = ตัวบล็อก;
ถ้า (ข != โมฆะ) {
Interrupt0(); // เพียงเพื่อตั้งค่าสถานะขัดจังหวะ
b.interrupt(); //เรียกกลับ
กลับ;
-
-
ขัดจังหวะ0();
-
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้ Thread.stop, ระงับ, ดำเนินการต่อ และขัดจังหวะ คุณสามารถดูเอกสารประกอบของ sun เช่น http://download.oracle.com/javase/6/docs/technotes/guides/concurrency /threadPrimitiveDeprecation .html
สุดท้ายนี้ เรามาตอบคำถามก่อนหน้านี้กัน:
คำถามที่ 1: ความสัมพันธ์ระหว่างเมธอด Thread.interrupt() และ InterruptedException คืออะไร ข้อยกเว้น InterruptedException ถูกทริกเกอร์โดยการขัดจังหวะหรือไม่
คำตอบ: Thread.interrupt() จะทำการโยน InterruptedException เฉพาะใน Object.wait(), .Object.join() และ Object.sleep() เท่านั้น เป็นเรื่องปกติในบล็อกอื่นๆ เพียงแค่ตั้งค่าข้อมูลแฟล็กของ Thread และโปรแกรมจำเป็นต้องประมวลผลด้วยตัวเอง
คัดลอกรหัสรหัส ดังต่อไปนี้:
if (Thread.interrupted()) // ล้างสถานะขัดจังหวะ!
โยน InterruptedException ใหม่ ();
คัดลอกรหัสรหัส ดังต่อไปนี้:
if (Thread.interrupted()) // ล้างสถานะขัดจังหวะ!
โยน InterruptedException ใหม่ ();
คำถามที่ 2: Thread.interrupt() จะขัดจังหวะการทำงานของเธรดในสถานะใด วิ่งหรือบล็อก?
คำตอบ: วัตถุประสงค์ของการออกแบบ Thread.interrupt ส่วนใหญ่จะจัดการกับเธรดในสถานะบล็อก เช่น สถานะ wait() และ sleep() อย่างไรก็ตาม สามารถรองรับการยกเลิกงานได้ในระหว่างการออกแบบโปรแกรม และสามารถรองรับสถานะ RUNNING ได้ด้วย ตัวอย่างเช่น Object.join() และการออกแบบ nio channel บางอันที่รองรับการขัดจังหวะ
คำถามที่ 3: การเขียนโปรแกรมเธรดทั่วไปจำเป็นต้องให้ความสนใจกับการขัดจังหวะหรือไม่? วิธีจัดการกับมันโดยทั่วไป? มันใช้ทำอะไรได้บ้าง?
คำตอบ: การใช้งานขัดจังหวะ: ปลดบล็อกการดำเนินการ รองรับการยกเลิกงาน การล้างข้อมูล ฯลฯ
คำถามที่ 4: อะไรคือความแตกต่างระหว่าง LockSupport.park() และ unpark() และ object.wait() และ notify()?
คำตอบ:
1. วิชามีความแตกต่างกัน LockSuport ดำเนินการประมวลผลการบล็อกสำหรับเธรดเป็นหลัก โดยสามารถระบุวัตถุเป้าหมายของคิวการบล็อกและระบุเธรดเฉพาะที่จะปลุกในแต่ละครั้ง Object.wait() รับวัตถุเป็นมิติ บล็อกเธรดปัจจุบัน และปลุกเธรดเดียว (สุ่ม) หรือทั้งหมด
2. กลไกการดำเนินการมีความแตกต่างกัน แม้ว่า LockSuport จะสามารถระบุวัตถุวัตถุของจอภาพได้ แต่คิวการบล็อกของ LockSuport และ object.wait() จะไม่ตัดกัน คุณสามารถดูตัวอย่างการทดสอบได้ object.notifyAll() ไม่สามารถปลุกเธรดการบล็อกของ LockSupport ได้
คำถามที่ 5: การใช้วัตถุตัวบล็อกที่ส่งผ่านโดย LockSupport.park (ตัวบล็อกวัตถุ) คืออะไร?
คำตอบ: blcoker ที่เกี่ยวข้องจะถูกบันทึกไว้ในแอตทริบิวต์ parkBlocker ของ Thread สะดวกมากในการตรวจสอบออบเจ็กต์การบล็อกเฉพาะผ่านคำสั่ง jstack
คัดลอกรหัสรหัส ดังต่อไปนี้:
สวนสาธารณะโมฆะคงที่สาธารณะ (ตัวบล็อกวัตถุ) {
เธรด t = Thread.currentThread();
setBlocker(t, blocker); //ตั้งค่าคุณสมบัติ Thread.parkBlocker
unsafe.park(เท็จ, 0L);
setBlocker(t, null); // ล้างค่าของคุณสมบัติ Thread.parkBlocker
-
คัดลอกรหัสรหัส ดังต่อไปนี้:
สวนสาธารณะโมฆะคงที่สาธารณะ (ตัวบล็อกวัตถุ) {
เธรด t = Thread.currentThread();
setBlocker(t, blocker); //ตั้งค่าคุณสมบัติ Thread.parkBlocker
unsafe.park(เท็จ, 0L);
setBlocker(t, null); // ล้างค่าของคุณสมบัติ Thread.parkBlocker
-
คำอธิบาย javadoc เฉพาะของ LockSupport ก็ค่อนข้างชัดเจนเช่นกัน คุณสามารถอ่านได้ด้านล่าง:
คำถามที่ 6: LockSupport สามารถตอบสนองต่อเหตุการณ์ Thread.interrupt() ได้หรือไม่ InterruptedException จะถูกโยนทิ้งหรือไม่
คำตอบ: สามารถตอบสนองต่อเหตุการณ์ขัดจังหวะได้ แต่จะไม่ทำให้เกิด InterruptedException เกี่ยวกับการสนับสนุนของ LockSupport สำหรับ Thread.interrupte โปรดดูคำอธิบายใน javadoc ด้วย:
รหัสทดสอบที่เกี่ยวข้อง
คัดลอกรหัสรหัส ดังต่อไปนี้:
แพ็คเกจ com.agapple.cocurrent;
นำเข้า java.io.File;
นำเข้า java.io.FileInputStream;
นำเข้า java.lang.reflect.Field;
นำเข้า java.util.concurrent.TimeUnit;
นำเข้า java.util.concurrent.locks.LockSupport;
LockSupportTest ระดับสาธารณะ {
ตัวบล็อก LockSupportTest แบบคงที่ส่วนตัว = LockSupportTest ใหม่ ();
โมฆะคงที่สาธารณะ main (String args []) พ่นข้อยกเว้น {
ล็อค SupportTest ();
พาร์คเทส();
ขัดจังหวะ ParkTest();
ขัดจังหวะ SleepTest ();
ขัดจังหวะรอทดสอบ();
-
-
* หลังจากอ็อบเจ็กต์ LockSupport.park ให้ลองรับอ็อบเจ็กต์ Thread.blocker และเรียกการปลุกครั้งเดียว
-
* @throwsException
-
โมฆะคงที่ส่วนตัว lockSupportTest () พ่นข้อยกเว้น {
เธรด t = doTest (TestCallBack ใหม่ () {
@แทนที่
โมฆะการโทรกลับสาธารณะ () พ่นข้อยกเว้น {
// ลองนอน 5 วินาที
System.out.println("ตัวบล็อก");
LockSupport.park(ตัวบล็อก);
System.out.println("ตื่นเดี๋ยวนี้!");
-
@แทนที่
สตริงสาธารณะ getName() {
กลับ "ล็อค SupportTest";
-
-
t.start(); // เริ่มอ่านกระทู้
เธรด.สลีป(150);
ซิงโครไนซ์ (ตัวบล็อก) {
ฟิลด์ฟิลด์ = Thread.class.getDeclaredField("parkBlocker");
field.setAccessible(จริง);
วัตถุ fBlocker = field.get(t);
System.out.println(ตัวบล็อก == fBlocker);
เธรด.สลีป(100);
System.out.println("แจ้งเตือนทั้งหมด");
blocker.notifyAll();
-
-
-
* หากคุณพยายามขัดจังหวะ object.wait() InterruptedException ที่เกี่ยวข้องจะถูกส่งออกไป
-
* @throws InterruptedException
-
โมฆะคงที่ส่วนตัว InterruptedWaitTest () พ่น InterruptedException {
วัตถุสุดท้าย obj = วัตถุใหม่ ();
เธรด t = doTest (TestCallBack ใหม่ () {
@แทนที่
โมฆะการโทรกลับสาธารณะ () พ่นข้อยกเว้น {
// ลองนอน 5 วินาที
obj.รอ();
System.out.println("ตื่นเดี๋ยวนี้!");
-
@แทนที่
สตริงสาธารณะ getName() {
กลับ "ขัดจังหวะรอทดสอบ";
-
-
t.start(); // เริ่มอ่านกระทู้
Thread.sleep (2000);
t.interrupt(); // ตรวจสอบว่ามีการตอบสนองต่อการขัดจังหวะระหว่างจอดหรือไม่
-
-
* หากคุณพยายามขัดจังหวะ Thread.sleep() InterruptedException ที่เกี่ยวข้องจะถูกส่งออกไป
-
* @throws InterruptedException
-
โมฆะคงที่ส่วนตัว InterruptSleepTest () พ่น InterruptedException {
เธรด t = doTest (TestCallBack ใหม่ () {
@แทนที่
โมฆะการโทรกลับสาธารณะ () พ่นข้อยกเว้น {
// ลองนอน 5 วินาที
เธรด.สลีป(5000);
System.out.println("ตื่นเดี๋ยวนี้!");
-
@แทนที่
สตริงสาธารณะ getName() {
กลับ "ขัดจังหวะ SleepTest";
-
-
t.start(); // เริ่มอ่านกระทู้
Thread.sleep (2000);
t.interrupt(); // ตรวจสอบว่ามีการตอบสนองต่อการขัดจังหวะระหว่างจอดหรือไม่
-
-
* พยายามขัดจังหวะ LockSupport.park() จะมีการตอบกลับแต่จะไม่มีข้อยกเว้น InterruptedException ถูกส่งออกไป
-
* @throws InterruptedException
-
โมฆะคงที่ส่วนตัว InterruptedException () พ่น InterruptedException {
เธรด t = doTest (TestCallBack ใหม่ () {
@แทนที่
โมฆะการโทรกลับสาธารณะ () {
//ลองจอดกระทู้ของตัวเองดู
LockSupport.parkNanos (ตัวบล็อก TimeUnit.SECONDS.toNanos (5));
System.out.println("ตื่นเดี๋ยวนี้!");
-
@แทนที่
สตริงสาธารณะ getName() {
กลับ "interruptParkTest";
-
-
t.start(); // เริ่มอ่านกระทู้
Thread.sleep (2000);
t.interrupt(); // ตรวจสอบว่ามีการตอบสนองต่อการขัดจังหวะระหว่างจอดหรือไม่
-
-
* ลองขัดจังหวะ LockSupport.unPark() แล้วจะมีการตอบกลับ
-
* @throws InterruptedException
-
โมฆะคงที่ส่วนตัว parkTest () พ่น InterruptedException {
เธรด t = doTest (TestCallBack ใหม่ () {
@แทนที่
โมฆะการโทรกลับสาธารณะ () {
//ลองจอดกระทู้ของตัวเองดู
LockSupport.park(ตัวบล็อก);
System.out.println("ตื่นเดี๋ยวนี้!");
-
@แทนที่
สตริงสาธารณะ getName() {
กลับ "parkTest";
-
-
t.start(); // เริ่มอ่านกระทู้
Thread.sleep (2000);
LockSupport.unpark(t);
t.ขัดจังหวะ();
-
สาธารณะ doTest เธรดคงที่ (การโทร TestCallBack สุดท้าย) {
คืนเธรดใหม่ () {
@แทนที่
โมฆะสาธารณะวิ่ง () {
ไฟล์ file = new File("/dev/urandom"); // อ่าน linux black hole
พยายาม {
FileInputStream ใน = FileInputStream ใหม่ (ไฟล์);
ไบต์ [] ไบต์ = ไบต์ใหม่ [1024];
ในขณะที่ (in.read(ไบต์, 0, 1024) > 0) {
ถ้า (Thread.interrupted()) {
โยน InterruptedException ใหม่ ("");
-
System.out.println(ไบต์[0]);
เธรด.สลีป(100);
เริ่มต้นนาน = System.currentTimeMillis();
โทร.โทรกลับ();
System.out.println(call.getName() + " ค่าใช้จ่ายในการโทรกลับ : "
+ (System.currentTimeMillis() - เริ่มต้น));
-
} จับ (ข้อยกเว้นจ) {
e.printStackTrace();
-
-
-
-
-
อินเทอร์เฟซ TestCallBack {
โมฆะการโทรกลับสาธารณะ () พ่นข้อยกเว้น;
สาธารณะสตริงgetName();
-
คัดลอกรหัสรหัส ดังต่อไปนี้:
แพ็คเกจ com.agapple.cocurrent;
นำเข้า java.io.File;
นำเข้า java.io.FileInputStream;
นำเข้า java.lang.reflect.Field;
นำเข้า java.util.concurrent.TimeUnit;
นำเข้า java.util.concurrent.locks.LockSupport;
LockSupportTest ระดับสาธารณะ {
ตัวบล็อก LockSupportTest แบบคงที่ส่วนตัว = LockSupportTest ใหม่ ();
โมฆะคงที่สาธารณะ main (String args []) พ่นข้อยกเว้น {
ล็อค SupportTest ();
พาร์คเทส();
ขัดจังหวะ ParkTest();
ขัดจังหวะ SleepTest ();
ขัดจังหวะรอทดสอบ();
-
-
* หลังจากอ็อบเจ็กต์ LockSupport.park ให้ลองรับอ็อบเจ็กต์ Thread.blocker และเรียกการปลุกครั้งเดียว
-
* @throwsException
-
โมฆะคงที่ส่วนตัว lockSupportTest () พ่นข้อยกเว้น {
เธรด t = doTest (TestCallBack ใหม่ () {
@แทนที่
โมฆะการโทรกลับสาธารณะ () พ่นข้อยกเว้น {
// ลองนอน 5 วินาที
System.out.println("ตัวบล็อก");
LockSupport.park(ตัวบล็อก);
System.out.println("ตื่นเดี๋ยวนี้!");
-
@แทนที่
สตริงสาธารณะ getName() {
กลับ "ล็อค SupportTest";
-
-
t.start(); // เริ่มอ่านกระทู้
เธรด.สลีป(150);
ซิงโครไนซ์ (ตัวบล็อก) {
ฟิลด์ฟิลด์ = Thread.class.getDeclaredField("parkBlocker");
field.setAccessible(จริง);
วัตถุ fBlocker = field.get(t);
System.out.println(ตัวบล็อก == fBlocker);
เธรด.สลีป(100);
System.out.println("แจ้งเตือนทั้งหมด");
blocker.notifyAll();
-
-
-
* หากคุณพยายามขัดจังหวะ object.wait() InterruptedException ที่เกี่ยวข้องจะถูกส่งออกไป
-
* @throws InterruptedException
-
โมฆะคงที่ส่วนตัว InterruptedWaitTest () พ่น InterruptedException {
วัตถุสุดท้าย obj = วัตถุใหม่ ();
เธรด t = doTest (TestCallBack ใหม่ () {
@แทนที่
โมฆะการโทรกลับสาธารณะ () พ่นข้อยกเว้น {
// ลองนอน 5 วินาที
obj.รอ();
System.out.println("ตื่นเดี๋ยวนี้!");
-
@แทนที่
สตริงสาธารณะ getName() {
กลับ "ขัดจังหวะรอทดสอบ";
-
-
t.start(); // เริ่มอ่านกระทู้
Thread.sleep (2000);
t.interrupt(); // ตรวจสอบว่ามีการตอบสนองต่อการขัดจังหวะระหว่างจอดหรือไม่
-
-
* หากคุณพยายามขัดจังหวะ Thread.sleep() InterruptedException ที่เกี่ยวข้องจะถูกส่งออกไป
-
* @throws InterruptedException
-
โมฆะคงที่ส่วนตัว InterruptSleepTest () พ่น InterruptedException {
เธรด t = doTest (TestCallBack ใหม่ () {
@แทนที่
โมฆะการโทรกลับสาธารณะ () พ่นข้อยกเว้น {
// ลองนอน 5 วินาที
เธรด.สลีป(5000);
System.out.println("ตื่นเดี๋ยวนี้!");
-
@แทนที่
สตริงสาธารณะ getName() {
กลับ "ขัดจังหวะ SleepTest";
-
-
t.start(); // เริ่มอ่านกระทู้
Thread.sleep (2000);
t.interrupt(); // ตรวจสอบว่ามีการตอบสนองต่อการขัดจังหวะระหว่างจอดหรือไม่
-
-
* พยายามขัดจังหวะ LockSupport.park() จะมีการตอบกลับแต่จะไม่มีข้อยกเว้น InterruptedException ถูกส่งออกไป
-
* @throws InterruptedException
-
โมฆะคงที่ส่วนตัว InterruptedException () พ่น InterruptedException {
เธรด t = doTest (TestCallBack ใหม่ () {
@แทนที่
โมฆะการโทรกลับสาธารณะ () {
//ลองจอดกระทู้ของตัวเองดู
LockSupport.parkNanos (ตัวบล็อก TimeUnit.SECONDS.toNanos (5));
System.out.println("ตื่นเดี๋ยวนี้!");
-
@แทนที่
สตริงสาธารณะ getName() {
กลับ "interruptParkTest";
-
-
t.start(); // เริ่มอ่านกระทู้
Thread.sleep (2000);
t.interrupt(); // ตรวจสอบว่ามีการตอบสนองต่อการขัดจังหวะระหว่างจอดหรือไม่
-
-
* ลองขัดจังหวะ LockSupport.unPark() แล้วจะมีการตอบกลับ
-
* @throws InterruptedException
-
โมฆะคงที่ส่วนตัว parkTest () พ่น InterruptedException {
เธรด t = doTest (TestCallBack ใหม่ () {
@แทนที่
โมฆะการโทรกลับสาธารณะ () {
//ลองจอดกระทู้ของตัวเองดู
LockSupport.park(ตัวบล็อก);
System.out.println("ตื่นเดี๋ยวนี้!");
-
@แทนที่
สตริงสาธารณะ getName() {
กลับ "parkTest";
-
-
t.start(); // เริ่มอ่านกระทู้
Thread.sleep (2000);
LockSupport.unpark(t);
t.ขัดจังหวะ();
-
สาธารณะ doTest เธรดคงที่ (การโทร TestCallBack สุดท้าย) {
คืนเธรดใหม่ () {
@แทนที่
โมฆะสาธารณะวิ่ง () {
ไฟล์ file = new File("/dev/urandom"); // อ่าน linux black hole
พยายาม {
FileInputStream ใน = FileInputStream ใหม่ (ไฟล์);
ไบต์ [] ไบต์ = ไบต์ใหม่ [1024];
ในขณะที่ (in.read (ไบต์, 0, 1024) > 0) {
ถ้า (Thread.interrupted()) {
โยน InterruptedException ใหม่ ("");
-
System.out.println(ไบต์[0]);
เธรด.สลีป(100);
เริ่มต้นนาน = System.currentTimeMillis();
โทร.โทรกลับ();
System.out.println(call.getName() + " ต้นทุนการโทรกลับเสร็จสิ้น : "
+ (System.currentTimeMillis() - เริ่มต้น));
-
} จับ (ข้อยกเว้นจ) {
e.printStackTrace();
-
-
-
-
-
อินเทอร์เฟซ TestCallBack {
โมฆะการโทรกลับสาธารณะ () พ่นข้อยกเว้น;
สาธารณะสตริงgetName();
-
ในที่สุด <BR>ฉันก็พบว่าบทความนี้เริ่มยาวขึ้นเรื่อยๆ เลยโพสต์ลงฟอรั่มให้ทุกคนได้พูดคุยกัน สุดท้ายบทความก็อธิบายแค่เนื้อหาระดับการใช้งานบางส่วนเท่านั้น และไม่ได้แนะนำ Thread จากการดำเนินงาน หรือการนำระบบ Sun Native ไปใช้ สำหรับกลไกบางอย่าง Daniumen ที่คุ้นเคยกับเรื่องนี้ก็สามารถแสดงความคิดเห็นได้เช่นกัน