1. กระบวนการและเธรด
1. กระบวนการคืออะไร?
คำจำกัดความแคบ: กระบวนการเป็นอินสแตนซ์ของโปรแกรมคอมพิวเตอร์ที่กำลังดำเนินการ
คำจำกัดความทั่วไป: กระบวนการเป็นกิจกรรมที่ทำงานของโปรแกรมที่มีฟังก์ชั่นอิสระบางอย่างเกี่ยวกับชุดข้อมูลที่แน่นอน มันเป็นหน่วยพื้นฐานของการดำเนินการแบบไดนามิกของระบบปฏิบัติการ ในระบบปฏิบัติการแบบดั้งเดิมกระบวนการเป็นทั้งหน่วยจัดสรรพื้นฐานและหน่วยดำเนินการพื้นฐาน
2. กระทู้คืออะไร?
เธรดบางครั้งเรียกว่ากระบวนการที่มีน้ำหนักเบา (LWP) เป็นหน่วยที่เล็กที่สุดของการไหลของโปรแกรม เธรดมาตรฐานประกอบด้วย ID เธรด, ตัวชี้คำสั่งปัจจุบัน (PC), ชุดของการลงทะเบียนและสแต็ก นอกจากนี้เธรดเป็นเอนทิตีในกระบวนการและเป็นหน่วยพื้นฐานที่กำหนดและจัดส่งโดยระบบอย่างอิสระ เธรดเองไม่ได้เป็นเจ้าของทรัพยากรระบบ แต่มีทรัพยากรที่จำเป็นเพียงไม่กี่แห่งในระหว่างการดำเนินการ แต่สามารถแบ่งปันทรัพยากรทั้งหมดที่เป็นเจ้าของโดยกระบวนการกับเธรดอื่น ๆ ที่อยู่ในกระบวนการเดียวกัน
3. ความแตกต่างระหว่างกระบวนการและเธรดคืออะไร?
ความแตกต่างที่สำคัญระหว่างกระบวนการและเธรดคือพวกเขาเป็นวิธีการจัดการทรัพยากรระบบปฏิบัติการที่แตกต่างกัน
กระบวนการมีพื้นที่ที่อยู่อิสระ หลังจากกระบวนการล่มมันจะไม่ส่งผลกระทบต่อกระบวนการอื่น ๆ ในโหมดที่ได้รับการป้องกันและเธรดเป็นเพียงเส้นทางการดำเนินการที่แตกต่างกันในกระบวนการ
เธรดมีสแต็กของตัวเองและตัวแปรท้องถิ่น แต่ไม่มีพื้นที่ที่อยู่แยกต่างหากระหว่างเธรด หากเธรดตายก็หมายความว่ากระบวนการทั้งหมดจะตาย ดังนั้นโปรแกรมหลายกระบวนการจึงมีความแข็งแกร่งมากกว่าโปรแกรมหลายเธรด แต่เมื่อเปลี่ยนกระบวนการพวกเขาใช้ทรัพยากรมากขึ้นและมีประสิทธิภาพน้อยกว่า อย่างไรก็ตามสำหรับการดำเนินการที่เกิดขึ้นพร้อมกันบางอย่างที่ต้องใช้การดำเนินการพร้อมกันที่ต้องใช้การแบ่งปันตัวแปรบางตัวพวกเขาสามารถใช้เธรดได้เท่านั้นไม่ใช่กระบวนการ
ในระยะสั้นความแตกต่างระหว่างเธรดและกระบวนการคือ:
(1) โปรแกรมมีกระบวนการอย่างน้อยหนึ่งกระบวนการและกระบวนการมีอย่างน้อยหนึ่งเธรด
(2) ระดับการแบ่งของเธรดมีขนาดเล็กกว่ากระบวนการทำให้การเกิดขึ้นพร้อมกันของโปรแกรมมัลติเธรดสูง
(3) กระบวนการมีหน่วยหน่วยความจำอิสระในระหว่างการดำเนินการและหลายเธรดแบ่งปันหน่วยความจำซึ่งช่วยปรับปรุงประสิทธิภาพการทำงานของโปรแกรมอย่างมาก
(4) มีความแตกต่างระหว่างเธรดและกระบวนการในระหว่างการดำเนินการ แต่ละเธรดอิสระมีรายการสำหรับการดำเนินการโปรแกรมลำดับการดำเนินการและการออกสำหรับโปรแกรม อย่างไรก็ตามเธรดไม่สามารถดำเนินการได้อย่างอิสระและต้องมีอยู่ในแอปพลิเคชันและแอปพลิเคชันการควบคุมการดำเนินการหลายเธรดนั้นมีให้โดยแอปพลิเคชัน
(5) จากมุมมองเชิงตรรกะความหมายของมัลติเธรดอยู่ในนั้นในแอปพลิเคชันสามารถดำเนินการส่วนการดำเนินการหลายชิ้นในเวลาเดียวกัน อย่างไรก็ตามระบบปฏิบัติการไม่ถือว่าหลายเธรดเป็นแอพพลิเคชั่นอิสระหลายรายการเพื่อให้ตระหนักถึงการกำหนดเวลากระบวนการการจัดการและการจัดสรรทรัพยากร
นี่คือความแตกต่างที่สำคัญระหว่างกระบวนการและเธรด
2. วงจรชีวิตของเธรดและสถานะพื้นฐานทั้งห้า
กระทู้ Java มีห้าสถานะพื้นฐาน:
(1) สถานะใหม่ (ใหม่): เมื่อสร้างคู่วัตถุเธรดมันจะเข้าสู่สถานะใหม่เช่น: เธรด t = new mythread ();
(2) ready state (runnable): เมื่อวิธีการเริ่มต้น () ของวัตถุเธรด (t.start ();) เธรดจะเข้าสู่สถานะพร้อม เธรดในสถานะพร้อมหมายความว่าเธรดพร้อมและกำลังรอให้ CPU กำหนดเวลาดำเนินการได้ตลอดเวลาไม่ใช่ว่าเธรดจะดำเนินการทันทีหลังจาก T.Start () ถูกดำเนินการ;
(3) การเรียกใช้สถานะ: เมื่อ CPU เริ่มกำหนดเวลาเธรดในสถานะพร้อมเธรดสามารถดำเนินการได้อย่างแท้จริงนั่นคือมันจะเข้าสู่สถานะการทำงาน หมายเหตุ: สถานะพร้อมเป็นเพียงรายการเดียวที่อยู่ในสถานะการทำงานนั่นคือถ้าเธรดต้องการเข้าสู่สถานะการรันเพื่อดำเนินการจะต้องอยู่ในสถานะพร้อมก่อน
(4) สถานะที่ถูกปิดกั้น: ด้วยเหตุผลบางอย่างเธรดในสถานะการรันชั่วคราวให้การใช้งาน CPU ชั่วคราวและหยุดการดำเนินการ ในเวลานี้มันเข้าสู่สถานะการบล็อก CPU จะไม่มีโอกาสถูกเรียกโดย CPU อีกครั้งเพื่อเข้าสู่สถานะการทำงาน ตามเหตุผลของการบล็อกสถานะการบล็อกสามารถแบ่งออกเป็นสามประเภท:
①รอการปิดกั้น: เธรดในสถานะการรันจะดำเนินการวิธีการรอ () เพื่อให้เธรดป้อนการรอการปิดกั้นสถานะ;
②การปิดกั้นแบบซิงโครไนซ์: เธรดไม่สามารถรับการล็อคซิงโครไนซ์ซิงโครไนซ์ (เนื่องจากล็อคถูกครอบครองโดยเธรดอื่น ๆ ) และจะเข้าสู่สถานะการปิดกั้นแบบซิงโครไนซ์;
③การบล็อกอื่น ๆ : เมื่อโทรไปที่เธรด sleep () หรือเข้าร่วม () หรือส่งคำขอ I/O เธรดจะป้อนสถานะการบล็อก เมื่อสถานะการนอนหลับ () หมดเวลาเข้าร่วม () รอให้เธรดยุติหรือหมดเวลาหรือการประมวลผล I/O เสร็จสิ้นเธรดจะกลับเข้าสู่สถานะพร้อมอีกครั้ง
(5) Dead State: เธรดเสร็จสิ้นการดำเนินการหรือออกจากวิธีการเรียกใช้ () เนื่องจากข้อยกเว้นและเธรดจะสิ้นสุดวัฏจักรชีวิต
3. การใช้งาน Java Multithreading
ใน Java หากคุณต้องการใช้โปรแกรมมัลติเธรดคุณต้องพึ่งพาคลาสหลักของเธรด (เช่นแนวคิดของคลาสหลักซึ่งแสดงถึงคลาสหลักของเธรด) แต่คลาสหลักของเธรดนี้จำเป็นต้องมีข้อกำหนดพิเศษบางอย่างเมื่อกำหนด คลาสนี้สามารถสืบทอดคลาสเธรดหรือใช้อินเทอร์เฟซ Runnable เพื่อกรอกคำจำกัดความ
1. สืบทอดคลาสเธรดเพื่อใช้มัลติเธรด
java.lang.thread เป็นคลาสที่รับผิดชอบในการดำเนินการเธรด คลาสใด ๆ สามารถกลายเป็นคลาสหลักของเธรดได้หากสืบทอดคลาสเธรด เนื่องจากเป็นคลาสหลักจึงต้องมีวิธีการใช้งานและวิธีการหลักที่เริ่มต้นโดยเธรดจำเป็นต้องเขียนทับวิธีการเรียกใช้ () ในคลาสเธรด
กำหนดคลาสร่างกายของด้าย:
คลาส MyThread ขยายเธรด {// คลาสหลักของหัวข้อสตริงส่วนตัวเธรด; Public Mythread (ชื่อสตริง) {this.title = title; } @Override โมฆะสาธารณะเรียกใช้ () {// วิธีหลักของเธรดสำหรับ (int x = 0; x <10; x ++) {system.out.println (this.title + "run, x =" + x); -ตอนนี้มีคลาสเธรดและมีวิธีการทำงานที่สอดคล้องกันในนั้นวัตถุควรสร้างขึ้นและควรเรียกใช้วิธีการภายในดังนั้นโปรแกรมต่อไปนี้จะถูกเขียนขึ้น:
Public Class TestDemo {โมฆะคงที่สาธารณะหลัก (String [] args) {MyThread MT1 = New MyThread ("Thread A"); MYTHREAD MT2 = NEW MYTHREAD ("Thread B"); MYTHREAD MT3 = NEW MYTHREAD ("Thread C"); mt1.run (); mt2.run (); mt3.run (); -ผลการทำงาน:
เธรด A รัน x = 0
เธรด A รัน x = 1
เธรด A รัน x = 2
เธรด A รัน x = 3
เธรด A รัน x = 4
เธรด A Runs, x = 5
เธรด A รัน x = 6
เธรด A Runs, x = 7
เธรด A รัน x = 8
เธรด A Runs, x = 9
เธรด B รัน, x = 0
เธรด B รัน, x = 1
เธรด b ทำงาน, x = 2
เธรด B รัน, x = 3
เธรด B รัน, x = 4
เธรด B รัน, x = 5
เธรด B รัน, x = 6
เธรด B รัน, x = 7
เธรด B รัน, x = 8
เธรด B รัน, x = 9
เธรด c รัน, x = 0
เธรด C รัน, x = 1
เธรด C รัน, x = 2
เธรด C รัน, x = 3
เธรด C รัน, x = 4
เธรด C รัน, x = 5
เธรด C รัน, x = 6
เธรด C รัน, x = 7
เธรด C รัน, x = 8
เธรด C รัน, x = 9
เราพบว่าการดำเนินการข้างต้นไม่ได้เริ่มต้นมัลติเธรดจริง ๆ เนื่องจากการดำเนินการของหลายเธรดจะต้องเรียกใช้สลับกันและในเวลานี้มันจะดำเนินการตามลำดับและรหัสของแต่ละวัตถุจะดำเนินการต่อไปหลังจากรหัสของแต่ละวัตถุถูกดำเนินการ
หากคุณต้องการเริ่มต้นมัลติเธรดในโปรแกรมอย่างแท้จริงคุณต้องพึ่งพาวิธีการของคลาส Thread: Public Void Start () ซึ่งหมายความว่าคุณจะเริ่มทำมัลติเธรด หลังจากเรียกใช้วิธีนี้แล้ววิธีการเรียกใช้ () จะถูกเรียกทางอ้อม:
Public Class TestDemo {โมฆะคงที่สาธารณะหลัก (String [] args) {MyThread MT1 = New MyThread ("Thread A"); MYTHREAD MT2 = NEW MYTHREAD ("Thread B"); MYTHREAD MT3 = NEW MYTHREAD ("Thread C"); mt1.start (); mt2.start (); mt3.start (); -ผลการทำงาน:
เธรด c รัน, x = 0
เธรด A รัน x = 0
เธรด B รัน, x = 0
เธรด A รัน x = 1
เธรด C รัน, x = 1
เธรด A รัน x = 2
เธรด B รัน, x = 1
เธรด A รัน x = 3
เธรด A รัน x = 4
เธรด A Runs, x = 5
เธรด C รัน, x = 2
เธรด C รัน, x = 3
เธรด C รัน, x = 4
เธรด C รัน, x = 5
เธรด C รัน, x = 6
เธรด C รัน, x = 7
เธรด C รัน, x = 8
เธรด C รัน, x = 9
เธรด A รัน x = 6
เธรด A Runs, x = 7
เธรด A รัน x = 8
เธรด A Runs, x = 9
เธรด b ทำงาน, x = 2
เธรด B รัน, x = 3
เธรด B รัน, x = 4
เธรด B รัน, x = 5
เธรด B รัน, x = 6
เธรด B รัน, x = 7
เธรด B รัน, x = 8
เธรด B รัน, x = 9
ในเวลานี้คุณสามารถพบว่าหลายเธรดดำเนินการสลับกัน แต่ผลลัพธ์ของการดำเนินการแต่ละครั้งนั้นแตกต่างกัน ผ่านรหัสข้างต้นเราสามารถสรุปข้อสรุป: หากคุณต้องการเริ่มต้นเธรดคุณต้องพึ่งพาวิธีการเริ่มต้น () ของคลาสเธรดเพื่อดำเนินการ หลังจากเริ่มเธรดวิธีการเรียกใช้ () จะถูกเรียกโดยค่าเริ่มต้น
หลังจากเรียกวิธีการเริ่มต้น () ชุดของสิ่งที่ซับซ้อนเกิดขึ้น:
(1) เริ่มเธรดการดำเนินการใหม่ (พร้อมสแต็คโทรใหม่);
(2) เธรดจะถูกถ่ายโอนจากสถานะใหม่ไปยังสถานะที่ทำงานได้
(3) เมื่อเธรดได้รับโอกาสในการดำเนินการวิธีการเรียกใช้เป้าหมาย () จะทำงาน
หมายเหตุ: สำหรับ Java วิธีการ Run () ไม่มีอะไรพิเศษ เช่นเดียวกับวิธีการหลัก () หมายความว่าเธรดใหม่รู้ชื่อวิธี (และลายเซ็น) ของการโทร ดังนั้นจึงเป็นการถูกกฎหมายที่จะเรียกวิธีการเรียกใช้บน Runnable หรือ Thread แต่ไม่ได้เริ่มเธรดใหม่
คำอธิบาย: ทำไมคุณต้องโทรเริ่มต้น () แทนที่จะเรียกเรียกใช้โดยตรง () เมื่อเธรดเริ่มต้น?
เราพบว่าหลังจากการโทรเริ่มต้น () จริง ๆ แล้วมันดำเนินการวิธีการเรียกใช้ () ดังนั้นทำไมไม่เรียกใช้วิธีการเรียกใช้ () โดยตรง? เพื่ออธิบายปัญหานี้ให้เปิดซอร์สโค้ดของคลาสเธรดและสังเกตคำจำกัดความของวิธีการเริ่มต้น ():
การเริ่มต้นเป็นโมฆะแบบซิงโครไนซ์สาธารณะ () {ถ้า (ThreadStatus! = 0) โยน unlueLTHREADSTATEException ใหม่ (); group.add (นี่); บูลีนเริ่มต้น = false; ลอง {start0 (); เริ่มต้น = จริง; } ในที่สุด {ลอง {ถ้า (เริ่มต้น) {group.threadStartFailed (นี่); }} catch (istignore throwable) {}}} โมฆะดั้งเดิมเริ่มต้น start0 ();เปิดซอร์สโค้ดของวิธีนี้และก่อนอื่นคุณจะพบว่าวิธีนี้จะส่งข้อยกเว้น โดยทั่วไปหากวิธีการใช้โยนวัตถุข้อยกเว้นข้อยกเว้นนี้ควรถูกจับโดยใช้ลอง ... จับหรือโยนโดยใช้การโยนในการประกาศวิธีการ แต่ไม่มีอะไรในพื้นที่นี้ ทำไม เนื่องจากคลาสข้อยกเว้นนี้เป็นของคลาสย่อยของข้อยกเว้นรันไทม์ (RuntimeException):
java.lang.Object
|- java.lang.hrowable
|- java.lang.exception
|- java.lang.runtimeException
|- java.lang.illegalargumentException
|- java.lang.illegalthreadstateException
ข้อยกเว้นนี้จะถูกโยนลงเมื่อวัตถุเธรดเริ่มต้นซ้ำ ๆ นั่นคือวัตถุเธรดสามารถเริ่มต้นได้เพียงครั้งเดียว
หนึ่งในส่วนที่สำคัญที่สุดของวิธีการเริ่มต้น () คือวิธี start0 () และวิธีนี้ใช้คำจำกัดความคำหลักดั้งเดิม
คำหลักดั้งเดิมหมายถึงอินเทอร์เฟซ Native Java นั่นคือ Java ใช้เรียกฟังก์ชั่นฟังก์ชั่นของระบบปฏิบัติการดั้งเดิมเพื่อให้การดำเนินการพิเศษบางอย่างเสร็จสมบูรณ์ การพัฒนารหัสดังกล่าวแทบจะไม่ค่อยเห็นใน Java เพราะคุณสมบัติที่ใหญ่ที่สุดของ Java คือการพกพา หากโปรแกรมสามารถใช้กับระบบปฏิบัติการคงที่ความสามารถในการพกพาจะหายไปอย่างสมบูรณ์ดังนั้นการดำเนินการนี้จึงไม่ได้ใช้โดยทั่วไป
การใช้งานมัลติเธรดจะต้องได้รับการสนับสนุนจากระบบปฏิบัติการ จากนั้นวิธี start0 () ข้างต้นจริง ๆ แล้วคล้ายกับวิธีนามธรรมโดยไม่ต้องใช้วิธีการ วิธีการนี้ถูกส่งมอบให้กับ JVM เพื่อนำไปใช้นั่นคือ JVM ใน Windows อาจใช้วิธี A A Start0 () ในขณะที่ JVM ใน Linux อาจใช้วิธี B เพื่อใช้งาน start0 () แต่เมื่อโทรมันจะไม่สนใจวิธีการที่แตกต่างกัน
ดังนั้นในการดำเนินการแบบมัลติเธรดการใช้วิธีการเริ่มต้น () เพื่อเริ่มต้นการดำเนินการแบบมัลติเธรดต้องใช้การเรียกใช้ฟังก์ชันระบบปฏิบัติการ
2. ใช้อินเทอร์เฟซ Runnable เพื่อใช้งานมัลติเธรดมัลติเธรด
การใช้คลาสเธรดสามารถอำนวยความสะดวกในการใช้เธรดมัลติเธรด แต่ข้อเสียที่ใหญ่ที่สุดของวิธีนี้คือปัญหาของการสืบทอดเดี่ยว ด้วยเหตุนี้อินเทอร์เฟซ Runnable ยังสามารถใช้ใน Java เพื่อใช้มัลติเธรด คำจำกัดความของอินเทอร์เฟซนี้มีดังนี้:
อินเทอร์เฟซสาธารณะ Runnable {Public Void Run ();}ใช้การเธรดมัลติเธรดผ่านอินเทอร์เฟซ Runnable:
คลาส MyThread ใช้งาน Runnable {// ชื่อสตริงส่วนตัวคลาสหลักของเธรด; Public Mythread (ชื่อสตริง) {this.title = title; } @Override โมฆะสาธารณะ Run () {// วิธีหลักของเธรดสำหรับ (int x = 0; x <10; x ++) {system.out.println (this.title + "run, x =" + x); -สิ่งนี้ไม่ได้แตกต่างจากวิธีก่อนหน้านี้ในการสืบทอดคลาสเธรด แต่ข้อดีอย่างหนึ่งคือมันหลีกเลี่ยงข้อ จำกัด ของการสืบทอดเดี่ยว
แต่ปัญหาอยู่ที่นี่ ดังที่ได้กล่าวไว้ก่อนหน้านี้หากคุณต้องการเริ่มต้นมัลติเธรดคุณต้องพึ่งพาวิธีการเริ่มต้น () ของคลาสเธรด เมื่อคุณสืบทอดคลาสเธรดคุณสามารถสืบทอดวิธีนี้โดยตรงและใช้งานได้ แต่ตอนนี้คุณกำลังใช้อินเทอร์เฟซที่รันได้ หากไม่มีวิธีนี้คุณสามารถสืบทอดได้ คุณควรทำอย่างไร?
ในการแก้ปัญหานี้คุณยังต้องพึ่งพาคลาสเธรดเพื่อให้เสร็จสมบูรณ์ ตัวสร้างถูกกำหนดไว้ในคลาสเธรดเพื่อรับวัตถุอินเตอร์เฟส runnable:
กระทู้สาธารณะ (เป้าหมายที่เรียกใช้ได้);
เริ่มมัลติเธรดโดยใช้คลาสเธรด:
Public Class TestDemo {โมฆะสาธารณะคงที่หลัก (สตริง [] args) โยนข้อยกเว้น {MyThread mt1 = new mythread ("เธรด A"); MYTHREAD MT2 = NEW MYTHREAD ("Thread B"); MYTHREAD MT3 = NEW MYTHREAD ("Thread C"); เธรดใหม่ (MT1) .Start (); เธรดใหม่ (MT2) .start (); เธรดใหม่ (MT3) .start (); -ผลการทำงาน:
เธรด A รัน x = 0
เธรด B รัน, x = 0
เธรด B รัน, x = 1
เธรด c รัน, x = 0
เธรด b ทำงาน, x = 2
เธรด A รัน x = 1
เธรด B รัน, x = 3
เธรด C รัน, x = 1
เธรด C รัน, x = 2
เธรด B รัน, x = 4
เธรด B รัน, x = 5
เธรด A รัน x = 2
เธรด A รัน x = 3
เธรด A รัน x = 4
เธรด A Runs, x = 5
เธรด A รัน x = 6
เธรด A Runs, x = 7
เธรด A รัน x = 8
เธรด A Runs, x = 9
เธรด B รัน, x = 6
เธรด B รัน, x = 7
เธรด B รัน, x = 8
เธรด B รัน, x = 9
เธรด C รัน, x = 3
เธรด C รัน, x = 4
เธรด C รัน, x = 5
เธรด C รัน, x = 6
เธรด C รัน, x = 7
เธรด C รัน, x = 8
เธรด C รัน, x = 9
ในเวลานี้ไม่เพียง แต่การเริ่มต้นแบบมัลติเธรดจะประสบความสำเร็จ แต่ยังไม่มีข้อ จำกัด การสืบทอดเดียว
3. วิธีที่สามในการใช้มัลติเธรด: ใช้อินเทอร์เฟซ callable เพื่อใช้งานมัลติเธรดมัลติเธรด
มัลติเธรดโดยใช้อินเทอร์เฟซแบบ runnable สามารถหลีกเลี่ยงข้อ จำกัด ของการสืบทอดการสืบทอดเดี่ยว แต่มีปัญหาที่วิธีการเรียกใช้ () ในอินเทอร์เฟซ Runnable ไม่สามารถส่งคืนผลการดำเนินการได้ เพื่อแก้ปัญหานี้มีการจัดอินเตอร์เฟสใหม่: อินเทอร์เฟซ callable (java.util.concurrent.callable)
อินเทอร์เฟซสาธารณะ callable <v> {public v call () โยนข้อยกเว้น;}หลังจากดำเนินการเมธอดการโทร () ในอินเทอร์เฟซ callable ผลลัพธ์จะถูกส่งกลับ ประเภทของผลลัพธ์ที่ส่งคืนจะถูกกำหนดโดยทั่วไปในอินเตอร์เฟส callable
การดำเนินการเฉพาะของการใช้งานอินเทอร์เฟซ callable เพื่อใช้งานมัลติเธรดคือ:
สร้างคลาสการใช้งานของอินเทอร์เฟซ callable และใช้วิธี Clall (); จากนั้นใช้คลาส FutureTask เพื่อห่อวัตถุของคลาสการใช้งานที่เรียกได้และใช้วัตถุ FutureTask นี้เป็นเป้าหมายของวัตถุเธรดเพื่อสร้างเธรด
กำหนดคลาส Thread Body:
นำเข้า java.util.concurrent.callable; Class MyThread ดำเนินการ callable <string> {ตั๋ว INT ส่วนตัว = 10; @Override การเรียกสตริงสาธารณะ () พ่นข้อยกเว้น {สำหรับ (int i = 0; i <20; i ++) {ถ้า (this.ticket> 0) {system.out.println ("ขายตั๋วจำนวนคะแนนโหวตที่เหลืออยู่"+this.ticket -); }} return "ตั๋วถูกขายหมด"; -คลาสเธรดไม่รองรับอินเทอร์เฟซที่เรียกได้โดยตรง หลังจาก jdk1.5 มีการให้ชั้นเรียน:
java.util.concurrent.futuretask <v>
คลาสนี้ส่วนใหญ่รับผิดชอบในการทำงานของวัตถุอินเตอร์เฟสที่เรียกได้ โครงสร้างคำจำกัดความของมันมีดังนี้:
FutureTask ชั้นเรียนสาธารณะ <V>
ขยายวัตถุ
ใช้งาน RunnableFurture <v>
อินเทอร์เฟซ RunnableFurture มีคำจำกัดความต่อไปนี้:
อินเทอร์เฟซสาธารณะ runnablefurture <v>
ขยายการวิ่งได้ในอนาคต <v>
ตัวสร้างต่อไปนี้ถูกกำหนดไว้ในคลาส FutureTask:
Public FutureTask (callable <v> callable)
ตอนนี้คุณสามารถรับวัตถุอินเทอร์เฟซที่เรียกได้ผ่านคลาส FutureTask วัตถุประสงค์ของการรับคือการได้รับผลตอบแทนของวิธีการโทร ()
จากการวิเคราะห์ข้างต้นเราสามารถหาได้:
คลาส FutureTask สามารถรับวัตถุอินเทอร์เฟซที่เรียกได้และคลาส FutureTask ใช้อินเทอร์เฟซ RunnableFurture ซึ่งสืบทอดอินเตอร์เฟส Runnable
ดังนั้นเราสามารถเริ่มมัลติเธรดแบบนี้ได้:
Public Class TestDemo {โมฆะคงที่สาธารณะหลัก (สตริง [] args) โยนข้อยกเว้น {MyThread MT1 = new MyThread (); MYTHREAD MT2 = ใหม่ MYTHREAD (); FutureTask <String> task1 = New FutureTask <String> (MT1); // get call () วิธีการส่งคืนผลลัพธ์ futureTask <String> task2 = ใหม่ FutureTask <String> (MT2); // รับเมธอดโทร () เพื่อส่งคืนผลลัพธ์ // FutureTask คุณสามารถใช้การสร้างคลาสเธรดเพื่อรับวัตถุงานใหม่หัวข้อ (task1). start (); เธรดใหม่ (task2). start (); // หลังจากการดำเนินการแบบมัลติเธรดเสร็จสมบูรณ์คุณสามารถใช้เมธอด GET () ในอินเทอร์เฟซแม่ของ FutureTask ในอนาคตเพื่อรับ System.out.out.println ("ผลการส่งคืนของเธรด 1:"+task1.get ()); System.out.println ("ผลตอบแทนของเธรด 2:"+task2.get ()); -ผลการทำงาน:
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 10
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 10
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 9
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 8
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 7
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 9
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 6
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 8
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 5
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 7
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 4
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 6
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 3
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 5
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 2
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 4
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 1
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 3
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 2
ขายตั๋วจำนวนคะแนนที่เหลืออยู่คือ 1
ผลตอบแทนของเธรด 1: ตั๋วถูกขายหมดแล้ว ผลตอบแทนของเธรด 2: ตั๋วถูกขายหมดแล้ว
สรุป:
ข้างต้นอธิบายสามวิธีในการใช้มัลติเธรด สำหรับการเริ่มต้นเธรดพวกเขาทั้งหมดเรียกว่าวิธีการเริ่มต้น () ของวัตถุเธรด เป็นสิ่งสำคัญที่จะต้องทราบว่าวิธีการเริ่มต้น () ไม่สามารถเรียกได้สองครั้งในวัตถุเธรดเดียวกัน