1. เธรดและกระบวนการ
1. ความแตกต่างระหว่างเธรดและกระบวนการคืออะไร:
เธรดหมายถึงหน่วยปฏิบัติการที่สามารถเรียกใช้รหัสโปรแกรมในระหว่างการดำเนินการ ในภาษา Java เธรดมีสี่รัฐ: วิ่งพร้อมระงับและสิ้นสุด
กระบวนการหมายถึงโปรแกรมที่กำลังดำเนินการ เธรดก็กลายเป็นกระบวนการที่มีน้ำหนักเบาเมื่อพวกเขามีสิ่งที่ต้องทำ พวกเขามีหน่วยที่เล็กที่สุดของการดำเนินการโปรแกรม กระบวนการสามารถมีหลายเธรด แต่ละเธรดแชร์พื้นที่พลังงานภายในของโปรแกรม (เซ็กเมนต์รหัสส่วนข้อมูลและพื้นที่ฮีป) และทรัพยากรระดับกระบวนการบางอย่าง (เช่นเปิดไฟล์) แต่แต่ละเธรดมีพื้นที่ของตัวเอง
2. ทำไมต้องใช้หลายกระบวนการ ? <br /> ส่วนใหญ่มีแง่มุมต่อไปนี้ในระดับระบบปฏิบัติการ:
- การใช้มัลติเธรดสามารถลดเวลาตอบสนองของโปรแกรม หากการดำเนินการใช้เวลานานหรือติดอยู่ในการรอนานโปรแกรมจะไม่ตอบสนองต่อการดำเนินการเช่นเมาส์และคีย์บอร์ด หลังจากใช้มัลติเธรดเธรดที่ใช้เวลานานนี้สามารถจัดสรรให้กับเธรดแยกต่างหากสำหรับการดำเนินการทำให้โปรแกรมมีปฏิสัมพันธ์ที่ดีขึ้น
- การสร้างเธรดและการสลับค่าใช้จ่ายไม่แพงเมื่อเทียบกับกระบวนการในขณะที่การทำงานร่วมกันมีประสิทธิภาพมากในการแบ่งปันข้อมูล
-คอมพิวเตอร์ Multi-CPU หรือ Multi-Core มีความสามารถในการเรียกใช้มัลติเธรด หากมีการใช้กระบวนการเดียวทรัพยากรคอมพิวเตอร์จะไม่ถูกนำมาใช้ซ้ำส่งผลให้ทรัพยากรเสียจำนวนมาก การใช้มัลติเธรดบนคอมพิวเตอร์มัลติ CPU สามารถปรับปรุงการใช้งาน CPU
- การใช้มัลติเธรดสามารถทำให้โครงสร้างของโปรแกรมง่ายขึ้นและทำให้ง่ายต่อการเข้าใจและบำรุงรักษา
2. การสร้างเธรด <br /> โดยทั่วไปมีสามวิธีสำหรับการใช้แบบมัลติเธรดและสองวิธีแรกเป็นวิธีที่ใช้กันมากที่สุด:
1. สืบทอดคลาสเธรดและแทนที่วิธีการเรียกใช้ ()
เธรดเป็นอินสแตนซ์ที่ใช้อินเทอร์เฟซที่รันได้ ควรสังเกตว่าหลังจากเรียกเมธอด start () มันจะไม่เรียกใช้รหัสมัลติเธรดมัลติเธรดทันที แต่แทนที่จะทำให้เธรดทำงานแทน เมื่อใดที่จะเรียกใช้รหัสมัลติเธรดจะถูกกำหนดโดยระบบปฏิบัติการ
นี่คือขั้นตอนหลัก:
(1) กำหนดคลาสย่อยของคลาสเธรดและแทนที่วิธีการเรียกใช้ของคลาส วิธีการของวิธีการเรียกใช้แสดงถึงงานที่เธรดต้องการให้เสร็จสมบูรณ์ ดังนั้นวิธีการเรียกใช้ () เรียกว่าร่างกายการดำเนินการ
(2) สร้างอินสแตนซ์ของคลาสย่อยของเธรดนั่นคือสร้างวัตถุเธรด
(3) เรียกใช้วิธีการเริ่มต้น () ของวัตถุเธรดเพื่อเริ่มเธรด
Public Class TestThread ขยายเธรด {public void run () {system.out.println ("Hello World"); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {เธรด mthread = new testThread (); mthread.start (); - 2. ใช้อินเทอร์เฟซ Runnable และใช้วิธีการ Run () ของอินเตอร์เฟส
นี่คือขั้นตอนหลัก:
(1) ปรับแต่งคลาสและใช้งานอินเตอร์เฟส Runnable และใช้วิธีการ Run ()
(2) สร้างอินสแตนซ์ของคลาสย่อยของเธรดและยกตัวอย่างวัตถุเธรดด้วยวัตถุที่ใช้อินเตอร์เฟสที่เรียกใช้เป็นพารามิเตอร์
(3) เมธอดเริ่มต้น () การโทรเพื่อเริ่มเธรด
Public Class TestRunnable ใช้งานได้ Runnable {Public Void Run () {System.out.println ("Hello World"); }} คลาสสาธารณะ testRunnable {public static void main (string [] args) {testrunnable mTestrunnable = new testRunnable (); เธรด mthread = เธรดใหม่ (mtestrunnable); mthread.start (); - 3. ใช้อินเทอร์เฟซ callable และแทนที่เมธอดการโทร ()
อินเทอร์เฟซ callable เป็นคลาสที่ใช้งานได้จริงในเฟรมเวิร์ก Executor อินเทอร์เฟซ callable นั้นคล้ายกับอินเทอร์เฟซ Runnable แต่ให้ฟังก์ชั่นที่ทรงพลังมากกว่า Runnable ซึ่งส่วนใหญ่จะปรากฏใน 3 คะแนนต่อไปนี้:
(1) Callable สามารถให้ค่าส่งคืนหลังจากที่ได้รับการยอมรับและ Runnable ไม่สามารถให้ฟังก์ชั่นนี้ได้
(2) เมธอดการโทร () ใน callable สามารถโยนข้อยกเว้นในขณะที่วิธีการเรียกใช้ () ของการเรียกใช้งานไม่สามารถโยนข้อยกเว้นได้
(3) การเรียกใช้ callable สามารถรับวัตถุในอนาคตได้ วัตถุในอนาคตแสดงถึงผลลัพธ์ของการคำนวณของอิบราฮิโมวิชและเขาให้วิธีการตรวจสอบว่าการคำนวณเสร็จสมบูรณ์หรือไม่ เนื่องจากเธรดเป็นของแบบจำลองการคำนวณแบบอะซิงโครนัสจึงเป็นไปไม่ได้ที่จะได้รับค่าส่งคืนของฟังก์ชันจากเธรดอื่น ในกรณีนี้ในอนาคตสามารถใช้ในการตรวจสอบเมธอดการโทร () เมื่อเธรดการเรียกใช้เมธอดการโทร () อย่างไรก็ตามเมื่อมีการเรียกวิธีการรับ () ในอนาคตเพื่อรับผลลัพธ์เธรดปัจจุบันจะบล็อกและทราบผลลัพธ์การส่งคืนของวิธีการโทร ()
Public Class TestCallable {// สร้างคลาส Public Class Public Static Class MyTestCallable ANPLEMENCE Callable {Public String Call () โยนข้อยกเว้น {retun "Hello World"; }} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myTestCallable mMyTestCallable = new myTestCallable (); ExecutorService MexecutorService = Executors.newsingLetHreadPool (); future mfuture = mexecutorservice.submit (mmytestcallable); ลอง {// รอให้เธรดสิ้นสุดและส่งคืน system.out.out.println (mfuture.get ()); } catch (exception e) {e.printstacktrace (); -ผลลัพธ์ผลลัพธ์ของโปรแกรมข้างต้นคือ: Hello World
ในบรรดาวิธีการทั้งสามนี้ขอแนะนำโดยทั่วไปในการใช้อินเทอร์เฟซที่ทำงานได้ เหตุผลคือ: อันดับแรกคลาสเธรดจะกำหนดวิธีการที่หลากหลายที่สามารถเขียนใหม่ได้โดยคลาสที่ได้รับ แต่จะต้องเขียนเมธอด Run () เท่านั้นซึ่งจะต้องรับรู้ฟังก์ชั่นหลักของเธรดนี้ซึ่งเป็นวิธีที่จำเป็นในการใช้อินเทอร์เฟซที่เรียกใช้ ประการที่สองชั้นเรียนควรได้รับการสืบทอดเมื่อพวกเขาจำเป็นต้องได้รับการเสริมความแข็งแกร่งหรือแก้ไข ดังนั้นหากไม่จำเป็นต้องแทนที่วิธีการอื่น ๆ ของคลาสเธรดคุณควรใช้อินเตอร์เฟส Runnable ในกรณีนี้
3. อินเตอร์รัปต์เธรด <br /> เธรดจะสิ้นสุดลงเมื่อเมธอด Run () ของเธรดดำเนินการคำสั่งสุดท้ายใน Body Method และส่งคืนโดยการดำเนินการคำสั่ง Return หรือเมื่อไม่มีข้อยกเว้นที่ไม่ติดอยู่ในวิธีการไม่ถูกจับ มีวิธีการหยุดใน Java รุ่นก่อนหน้าซึ่งเธรดอื่น ๆ สามารถเรียกให้ยุติเธรดได้ แต่วิธีนี้ได้เลิกใช้แล้ว
วิธีการขัดจังหวะสามารถใช้เพื่อขอยกเลิกเธรด เมื่อเธรดเรียกวิธีการขัดจังหวะสถานะการขัดจังหวะของเธรดจะถูกตั้งค่า นี่คือธงบูลีนที่ไม่มีเธรด แต่ละเธรดควรตรวจสอบธงนี้เป็นครั้งคราวเพื่อตรวจสอบว่าเธรดถูกขัดจังหวะหรือไม่
หากต้องการทราบว่ามีการตั้งค่าเธรดหรือไม่คุณสามารถเรียกเธรด currentthread (). isinterrupted ():
ในขณะที่ (! thread.currentthread (). isinterrupted ()) {ทำอะไร} อย่างไรก็ตามหากมีการปิดกั้นเธรดสถานะการขัดจังหวะไม่สามารถตรวจพบได้ นี่คือที่สร้างการขัดจังหวะการรับรู้ เมื่อมีการเรียกวิธีการขัดจังหวะในเธรดที่ถูกบล็อก (เรียกว่านอนหลับหรือรอ) การบล็อกการโทรจะถูกขัดจังหวะโดยการขัดจังหวะการรับรู้
หากวิธีการนอนหลับ (หรือวิธีการขัดจังหวะอื่น ๆ ) จะถูกเรียกหลังจากการวนซ้ำแต่ละครั้งการตรวจจับที่ไม่หยุดนิ่งนั้นไม่จำเป็นและไร้ประโยชน์ หากวิธีการนอนหลับถูกเรียกเมื่อตั้งค่าการขัดจังหวะมันจะไม่นอนหลับ แต่จะล้างสถานะและโยนการขัดจังหวะการรับรู้ ดังนั้นหากคุณเรียกการนอนหลับในวงอย่าตรวจจับสถานะการขัดจังหวะเพียงแค่จับการขัดจังหวะ
ในรหัสที่เผยแพร่จำนวนมากคุณจะพบว่า InterruptedException ถูกระงับในระดับต่ำมาก:
โมฆะ mytask () {... ลอง {sleep (50)} catch (interruptedexception e) {... }}อย่าทำเช่นนี้ หากคุณไม่คิดว่าจะมีประโยชน์ในการจับมีสองตัวเลือกที่สมเหตุสมผล:
Call Thread.CurrentThread (). Interrup () ใน Catch เพื่อตั้งค่าสถานะการขัดจังหวะ ผู้โทรสามารถตรวจจับได้ ตัวเลือกที่ดีกว่าคือการใช้ THROMPEDEXCEPTION เพื่อทำเครื่องหมายวิธีการของคุณโดยไม่ต้องใช้บล็อกคำสั่งลองเพื่อจับภาพที่เสร็จสมบูรณ์ วิธีนี้ผู้โทรสามารถจับข้อยกเว้นนี้ได้:
โมฆะ mytask () โยน interruptedexception {sleep (50)}}4. สถานะของเธรด
(1). สถานะใหม่ (ใหม่): วัตถุเธรดใหม่ถูกสร้างขึ้น
(2). ready state (runnable): หลังจากสร้างวัตถุเธรดเธรดอื่น ๆ เรียกวิธีการเริ่มต้น () ของวัตถุ เธรดในสถานะนี้อยู่ในพูลเธรดที่รันได้และกลายเป็นรันได้รอรับสิทธิ์การใช้งาน CPU
(3). การเรียกใช้สถานะ: เธรดในสถานะพร้อมรับ CPU และดำเนินการรหัสโปรแกรม
(4). สถานะที่ถูกบล็อก: สถานะที่ถูกบล็อกหมายความว่าเธรดจะให้สิทธิ์การใช้งาน CPU ด้วยเหตุผลบางอย่างและหยุดทำงานชั่วคราว มันไม่ได้จนกว่าเธรดจะเข้าสู่สถานะพร้อมที่จะมีโอกาสไปที่สถานะการวิ่ง การอุดตันมีสามประเภท:
- รอบล็อก: เธรดที่รันจะดำเนินการวิธีการรอ () และ JVM จะใส่เธรดลงในพูลรอ
- การปิดกั้นแบบซิงโครนัส: เมื่อเธรดที่รันอยู่จะได้รับการล็อคการซิงโครไนซ์ของวัตถุหากล็อคการซิงโครไนซ์ถูกครอบครองโดยเธรดอื่น JVM จะใส่เธรดลงในพูลล็อค
- การปิดกั้นอื่น ๆ : เมื่อเธรดที่รันเรียกใช้วิธีการ SLEEP () หรือเข้าร่วม () หรือออกคำขอ I/O JVM จะตั้งเธรดเป็นสถานะการบล็อก เมื่อสถานะการนอนหลับ () หมดเวลาเข้าร่วม () รอให้เธรดยุติหรือหมดเวลาหรือการประมวลผล I/O เสร็จสิ้นเธรดจะกลับเข้าสู่สถานะพร้อมอีกครั้ง
(5). Dead State: เธรดเสร็จสิ้นการดำเนินการหรือออกจากวิธีการเรียกใช้ () เนื่องจากข้อยกเว้นและเธรดจะสิ้นสุดวงจรชีวิต
5. ลำดับความสำคัญของด้ายและด้าย
1. ลำดับความสำคัญของเธรด
ใน Java แต่ละเธรดมีลำดับความสำคัญและโดยค่าเริ่มต้นเธรดจะสืบทอดลำดับความสำคัญของคลาสแม่ คุณสามารถใช้วิธีการ setPriority เพื่อเพิ่มหรือลดลำดับความสำคัญของเธรด ลำดับความสำคัญสามารถตั้งค่าเป็นค่าใด ๆ ระหว่าง min_priority (กำหนดเป็น 1 ในคลาสเธรด) และ max_priority (กำหนดเป็น 10 ในคลาสเธรด) ลำดับความสำคัญเริ่มต้นของเธรดคือ norm_priority (กำหนดเป็น 5 ในคลาสเธรด)
พยายามอย่าพึ่งพาลำดับความสำคัญ หากคุณต้องการใช้มันจริงๆคุณควรหลีกเลี่ยงข้อผิดพลาดทั่วไปที่ผู้เริ่มต้นทำ หากเธรดที่มีลำดับความสำคัญสูงหลายตัวไม่เข้าสู่สถานะที่ไม่ได้ใช้งานเธรดที่มีลำดับความสำคัญต่ำอาจไม่ถูกดำเนินการ เมื่อใดก็ตามที่ตัวกำหนดตารางเวลาตัดสินใจที่จะเรียกใช้เธรดใหม่ก่อนอื่นจะเลือกท่ามกลางเธรดที่มีลำดับความสำคัญแม้ว่าสิ่งนี้จะอดอยากเธรดที่มีลำดับความสำคัญต่ำอย่างสมบูรณ์
2. ด้ายดุล
โทร setdaemon (จริง); แปลงด้ายเป็นเธรด daemon จุดประสงค์เดียวของเธรด daemon คือการให้บริการกับเธรดอื่น ๆ เธรดเวลาเป็นตัวอย่าง มันส่งสัญญาณไปยังเธรดอื่นเป็นประจำหรือล้างเธรดที่ล้าสมัยที่บอกรายการแคช เมื่อมีเธรด daemon เท่านั้นที่เหลืออยู่เครื่องเสมือนจะออกเพราะถ้ามีเธรด daemon เท่านั้นที่เหลือจะไม่จำเป็นต้องเรียกใช้โปรแกรมต่อไป
นอกจากนี้คอลเลกชันขยะของ JVM การจัดการหน่วยความจำและเธรดอื่น ๆ คือเธรด daemon นอกจากนี้เมื่อทำแอปพลิเคชันฐานข้อมูลกลุ่มการเชื่อมต่อฐานข้อมูลที่ใช้ยังมีเธรดพื้นหลังจำนวนมากตรวจสอบจำนวนการเชื่อมต่อเวลาหมดเวลาสถานะ ฯลฯ
ข้างต้นเป็นเรื่องเกี่ยวกับคำจำกัดความของเธรดสถานะและคุณสมบัติของ Java multithreading ฉันหวังว่ามันจะเป็นประโยชน์กับการเรียนรู้ของทุกคน