1. แนวคิดของเธรด: เธรดหมายถึงโฟลว์การดำเนินการของงานตั้งแต่ต้นจนจบ เธรดมีกลไกในการทำงาน สำหรับ Java หลายเธรดสามารถดำเนินการพร้อมกันในโปรแกรมและเธรดเหล่านี้สามารถทำงานพร้อมกันในระบบมัลติโปรเซสเซอร์ เมื่อโปรแกรมทำงานเป็นแอปพลิเคชัน Java Interpreter จะเริ่มเธรดสำหรับวิธีการหลัก ()
2. ขนานและพร้อมกัน:
(1) การเกิดขึ้นพร้อมกัน: ในระบบโปรเซสเซอร์เดียวหลายเธรดแบ่งปันเวลา CPU และระบบปฏิบัติการมีหน้าที่รับผิดชอบในการกำหนดเวลาและการจัดสรรทรัพยากรให้กับพวกเขา
(2) Parallelism: ในระบบมัลติโปรเซสเซอร์โปรเซสเซอร์หลายตัวสามารถเรียกใช้หลายเธรดในเวลาเดียวกัน เธรดเหล่านี้สามารถทำงานพร้อมกันได้ในเวลาเดียวกัน ซึ่งแตกต่างจากการเกิดขึ้นพร้อมกันมีเพียงหลายเธรดเท่านั้นที่สามารถแชร์เวลา CPU และมีเพียงเธรดเดียวเท่านั้นที่สามารถทำงานได้ในเวลาเดียวกัน
3. การสร้างเธรด:
(1) แนวคิดพื้นฐาน: แต่ละงานใน Java เป็นวัตถุที่รันได้ ในการสร้างงานคลาสงานจะต้องถูกกำหนดก่อนและคลาสงานจะต้องใช้อินเตอร์เฟส Runnable และเธรดเป็นวัตถุที่สะดวกสำหรับการดำเนินงาน กระบวนการดำเนินการของเธรดคือการดำเนินการของวิธีการเรียกใช้ () ในคลาสงานจนกว่าจะสิ้นสุด
(2) สร้างเธรดผ่านอินเทอร์เฟซ Runnable:
. กำหนดคลาสงานเพื่อใช้งานอินเตอร์เฟส Runnable ใช้เมธอด Run () ในเมธอด Runnable Interface (The Run () บอกเธรดระบบวิธีการเรียกใช้) และกำหนดรหัสงานเฉพาะหรือตรรกะการประมวลผลในเมธอด Run ()
ข. หลังจากกำหนดคลาสงานให้สร้างวัตถุงานสำหรับคลาสงาน
ค. งานจะต้องดำเนินการในเธรดสร้างวัตถุของคลาส Tread และส่งผ่านวัตถุคลาสงานที่สร้างขึ้นก่อนหน้านี้ซึ่งใช้อินเตอร์เฟส Runnable ไปยังตัวสร้างของคลาส Tread เป็นพารามิเตอร์
d. เรียกเมธอด start () ของวัตถุคลาสดอกยางและเริ่มเธรด มันทำให้วิธีการเรียกใช้งาน () ของงานถูกดำเนินการ เมื่อวิธีการเรียกใช้ () ถูกดำเนินการเธรดจะสิ้นสุด
รหัสตัวอย่าง:
แพ็คเกจ com.muzeet.mutithread; // แต่ละงานเป็นอินสแตนซ์ของอินเทอร์เฟซที่เรียกใช้ได้ งานเป็นวัตถุที่สามารถเรียกใช้งานได้และเธรดเป็นวัตถุที่อำนวยความสะดวกในการดำเนินการของงาน คุณต้องสร้างคลาสงานและแทนที่วิธีการเรียกใช้เพื่อกำหนดระดับงานสาธารณะ threadDemo1 ใช้งาน andable {private int countdown = 10; @Override // เขียนวิธีเรียกใช้ใหม่และกำหนดโมฆะสาธารณะงานเรียกใช้ () {ในขณะที่ (นับถอยหลัง-> 0) {System.out.println ("$" + thread.currentthread (). getName () (" + CountDown +") "); }} // การเรียกวิธีการเริ่มต้นจะเริ่มเธรดทำให้เกิดวิธีการเรียกใช้ในงานที่จะเรียก หลังจากดำเนินการวิธีการรันแล้วเธรดจะสิ้นสุดโมฆะคงที่สาธารณะ (สตริง [] args) {runnable demo1 = threaddemo1 () ใหม่ (); เธรดเธรด 1 = เธรดใหม่ (demo1); เธรดเธรด 2 = เธรดใหม่ (demo1); Thread1.start (); Thread2.start (); System.out.println ("Rocket Launch Countdown:"); -โปรแกรมการรันผลลัพธ์:
Rocket Launch Countdown: $ thread-0 (9) $ thread-0 (8) $ thread-0 (7) $ thread-0 (6) $ thread-0 (5) $ thread-0 (4) $ thread-0 (3) $ thread-0 (2) $ thread-0 (1) $ thread-0 (0)
เรียกใช้วัตถุงานสองชิ้นในเวลาเดียวกัน:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {runnable demo1 = ใหม่ threadDemo1 (); runnable demo2 = new ThreadDemo1 (); เธรดเธรด 1 = เธรดใหม่ (demo1); เธรดเธรด 2 = เธรดใหม่ (demo2); Thread1.start (); Thread2.start (); System.out.println ("Rocket Launch Countdown:"); -ผลการทำงาน:
Rocket Launch Countdown: $ thread-0 (9) $ thread-0 (8) $ thread-0 (7) $ thread-0 (6) $ thread-1 (9) $ thread-0 (5) $ thread-1 (8) $ thread-0 (4) $ thread-1 (7) $ thread-0 (3) $ thread-1 (6) $ thread-1 (5) $ thread-0 (2) $ thread-1 (4) $ thread-1 (3) $ thread-1 (2) $ thread-1 (1) $ thread-1 (0) $ thread-0 (1) $ thread-0 (0)
(3) สืบทอดคลาสเธรดเพื่อสร้างเธรด:
. ก่อนอื่นสร้างคลาสงานขยายคลาสเธรด เนื่องจากคลาสเธรดใช้อินเทอร์เฟซ Runnable คลาสงานที่กำหนดเองจึงใช้วิธีการ Runnable Interface และ RERUN () ซึ่งกำหนดรหัสงานเฉพาะหรือตรรกะการประมวลผล
ข. สร้างวัตถุคลาสงานซึ่งสามารถใช้เธรดหรือเรียกใช้เป็นประเภทตัวแปรที่กำหนดเอง
ค. เรียกเมธอด start () ของวัตถุที่กำหนดเองและเริ่มเธรด
รหัสตัวอย่าง:
แพ็คเกจ com.muzeet.mutithread; // แต่ละงานเป็นอินสแตนซ์ของอินเทอร์เฟซที่เรียกใช้ได้ งานเป็นวัตถุที่สามารถเรียกใช้งานได้และเธรดสามารถเรียกใช้วัตถุได้ คลาสงานจะต้องถูกสร้างขึ้นและวิธีการเรียกใช้จะต้องถูกแทนที่เพื่อกำหนดระดับงานสาธารณะ ExtendFromThread ขยายเธรด {Private Int Countdown = 10; @Override // เขียนวิธีการเรียกใช้ใหม่และกำหนดโมฆะสาธารณะงาน Run () {ในขณะที่ (นับถอยหลัง-> 0) {System.out.println ("$" + this.getName () + "(" + CountDown + ")"); }} // การเรียกวิธีการเริ่มต้นจะเริ่มเธรดทำให้เกิดวิธีการเรียกใช้ในงานที่จะเรียก หลังจากดำเนินการวิธีการเรียกใช้แล้วเธรดจะสิ้นสุดโมฆะคงที่สาธารณะ (สตริง [] args) {ExtendFromThread Thread1 = ใหม่ ExtendFromThread (); ExtendFromThread Thread2 = ใหม่ ExtendFromThread (); Thread1.start (); Thread2.start (); System.out.println ("Rocket Launch Countdown:"); -ผลการทำงาน:
Rocket Launch Countdown: $ thread-0 (9) $ thread-0 (8) $ thread-0 (7) $ thread-0 (6) $ thread-0 (5) $ thread-0 (4) $ thread-0 (3) $ thread-0 (2) $ thread-0 (1) $ thread-0 (0) $ thread-1 (9) $ thread-1 (8) $ thread-1 (7) $ thread-1 (6) $ thread-1 (5) $ thread-1 (4) $ thread-1 (3) $ thread-1 (2) $ thread-1 (1) $ thread-1 (0)
เธรดหนึ่งรอให้เธรดอื่นสิ้นสุดลงก่อนที่จะดำเนินการ: เมื่อดำเนินการงาน printnum เมื่อพิมพ์หมายเลข 50 มันจะเปลี่ยนเป็นงานของการพิมพ์อักขระ C และจากนั้นก็ยังคงดำเนินการงานพิมพ์หมายเลขหลังจากเธรด
แพ็คเกจ com.muzeet.testthread; Public Class Printnum ใช้งาน Runnable {Private Int LastNum; publinum (int n) {lastNum = n; } @Override โมฆะสาธารณะ Run () {// todo วิธีการที่สร้างอัตโนมัติ stub เธรดเธรด 4 = เธรดใหม่ (printchar ใหม่ ('c', 40)); Thread4.start (); ลอง {สำหรับ (int i = 1; i <= lastNum; i ++) {system.out.println (""+i); if (i == 50) {thread4.join (); }}} catch (interruptedException e) {// toDo บล็อก catch ที่สร้างโดยอัตโนมัติ E.PrintStackTrace (); -4. การเปรียบเทียบสองวิธี (พิมพ์ซ้ำ)
ก่อนอื่นเราวิเคราะห์ผลลัพธ์ผลลัพธ์ของทั้งสองวิธี นอกจากนี้เรายังสร้างสองเธรด ทำไมผลลัพธ์จึงแตกต่างกัน?
การใช้อินเทอร์เฟซ Runnable เพื่อสร้างเธรดคุณสามารถแชร์วัตถุเป้าหมายเดียวกัน (TreadDemo1TT = newTreadDemo1 ();), การใช้เธรดที่เหมือนกันหลายรายการเพื่อประมวลผลทรัพยากรเดียวกัน เมื่อเธรดแรกเสร็จสิ้นงานการนับถอยหลังเป็น 0 อยู่แล้วดังนั้นเธรดที่สองจะไม่เอาต์พุต การสืบทอดวิธีการสร้างเธรดโดยเธรดวัตถุคลาสงานสองชิ้นถูกสร้างขึ้นพร้อมกับตัวแปรสมาชิกที่เกี่ยวข้องและพวกเขาจะไม่รบกวนกันและกัน
จากนั้นดูคำอธิบายจาก JDK:
อินเทอร์เฟซที่รันได้ควรดำเนินการโดยคลาสที่ตั้งใจจะดำเนินการอินสแตนซ์ของพวกเขาผ่านเธรดที่แน่นอน คลาสจะต้องกำหนดวิธีการแบบไม่มีพารามิเตอร์ที่เรียกว่า Run
จุดประสงค์ในการออกแบบอินเทอร์เฟซนี้คือการจัดทำโปรโตคอลสาธารณะสำหรับวัตถุที่ต้องการเรียกใช้รหัสเมื่อใช้งานอยู่ ตัวอย่างเช่นคลาสเธรดใช้งานได้ การเปิดใช้งานหมายความว่าเธรดเริ่มต้นขึ้นและยังไม่หยุด
นอกจากนี้ Runnable ยังให้วิธีการเปิดใช้งานสำหรับคลาสที่ไม่ใช่คลาสย่อยของเธรด ด้วยการสร้างอินสแตนซ์ของเธรดและนำตัวเองเป็นเป้าหมายที่กำลังทำงานอยู่คุณสามารถเรียกใช้คลาสที่ใช้งานได้ ในกรณีส่วนใหญ่หากคุณต้องการแทนที่วิธีการเรียกใช้ () และไม่แทนที่วิธีเธรดอื่น ๆ คุณควรใช้อินเทอร์เฟซ Runnable สิ่งนี้มีความสำคัญเนื่องจากหากโปรแกรมเมอร์ตั้งใจที่จะแก้ไขหรือปรับปรุงพฤติกรรมพื้นฐานของคลาสไม่ควรสร้างคลาสย่อยสำหรับคลาสนั้น (ขอแนะนำให้ใช้การสร้างคลาสงานและใช้อินเทอร์เฟซที่ทำงานได้แทนการสืบทอดคลาสเธรด)
นำมาใช้มรดกของคลาสเธรด:
(1) ข้อดี: เขียนง่าย หากคุณต้องการเข้าถึงเธรดปัจจุบันคุณไม่จำเป็นต้องใช้เมธอด thread.currentthread () คุณสามารถรับเธรดปัจจุบันได้โดยตรงโดยใช้สิ่งนี้
(2) ข้อเสีย: เนื่องจากคลาสเธรดได้สืบทอดคลาสเธรดจึงไม่สามารถสืบทอดคลาสพาเรนต์อื่น ๆ ได้
การใช้วิธีอินเตอร์เฟสแบบเรียกใช้:
(1) ข้อดี: คลาสเธรดใช้อินเตอร์เฟสที่สามารถเรียกใช้งานได้เท่านั้นและยังสามารถสืบทอดคลาสอื่น ๆ ได้ ด้วยวิธีนี้หลายเธรดสามารถแชร์วัตถุเป้าหมายเดียวกันได้ดังนั้นจึงเหมาะอย่างยิ่งสำหรับเธรดที่เหมือนกันหลายตัวเพื่อจัดการทรัพยากรเดียวกันเพื่อให้รหัส CPU และข้อมูลสามารถแยกออกเป็นรูปแบบที่ชัดเจนซึ่งสะท้อนแนวคิดเชิงวัตถุได้ดีขึ้น
(2) ข้อเสีย: การเขียนโปรแกรมมีความซับซ้อนเล็กน้อย หากคุณต้องการเข้าถึงเธรดปัจจุบันคุณต้องใช้เมธอด thread.currentthread ()
สรุป
ข้างต้นคือทั้งหมดเกี่ยวกับสองวิธีในการสร้างเธรดใน Java multithreading และตัวอย่างโค้ดเปรียบเทียบ ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!