Java multithreading คืออะไร
Java เป็นกลไกในการจัดการงานหลายอย่างพร้อมกัน (พร้อมกันและเป็นอิสระ) หลายเธรดอยู่ร่วมกันในกระบวนการ JVM เดียวกันดังนั้นพวกเขาจึงแบ่งปันพื้นที่หน่วยความจำเดียวกัน เมื่อเทียบกับหลายกระบวนการการสื่อสารระหว่างหลายเธรดนั้นเบากว่า ในความเข้าใจของฉัน Java multithreading เป็นการปรับปรุงการใช้งาน CPU กระทู้ Java มี 4 รัฐ: ใหม่, วิ่งได้, บล็อกและตาย กุญแจสำคัญคือการปิดกั้น การบล็อกหมายถึงการรอ เธรดการปิดกั้นไม่ได้เข้าร่วมในการจัดสรรเวลาของตัวแจกจ่ายเธรดดังนั้นโดยธรรมชาติแล้วจะไม่ใช้ CPU ในสภาพแวดล้อมแบบมัลติเธรดเธรดที่ไม่ถูกบล็อกเหล่านั้นทำงานและใช้ประโยชน์จาก CPU อย่างเต็มที่
สรุป 40 คำถาม
1. การใช้มัลติเธรดมีอะไรบ้าง?
คำถามที่อาจดูไร้สาระสำหรับหลาย ๆ คน: ฉันสามารถใช้มัลติเธรดได้ แต่การใช้งานคืออะไร? ในความคิดของฉันคำตอบนี้เป็นเรื่องไร้สาระมากขึ้น สิ่งที่เรียกว่า "รู้ว่าอะไรจริง" คือ "รู้ว่าอะไรจริง", "รู้ว่าอะไรจริง", "ทำไมใช้" คือ "รู้ว่าอะไรจริง" เพียงแค่ถึงระดับของ "การรู้ว่าอะไรจริง" เท่านั้นที่สามารถกล่าวได้ว่าสามารถใช้จุดความรู้ได้อย่างอิสระ โอเคให้ฉันบอกคุณว่าฉันคิดอย่างไรเกี่ยวกับปัญหานี้:
(1) ให้การเล่นอย่างเต็มที่กับข้อดีของ CPU แบบหลายคอร์
ด้วยความก้าวหน้าของอุตสาหกรรมแล็ปท็อปในปัจจุบันเดสก์ท็อปและแม้แต่เซิร์ฟเวอร์แอปพลิเคชันเชิงพาณิชย์ล้วนเป็นแบบดูอัลคอร์และ 4 คอร์, 8 คอร์หรือ 16 คอร์ไม่ใช่เรื่องแปลก หากเป็นโปรแกรมแบบเธรดเดี่ยว 50% จะสูญเปล่าใน CPU แบบดูอัลคอร์และ 75% จะสูญเปล่าใน CPU 4 คอร์ สิ่งที่เรียกว่า "มัลติเธรด" บนซีพียูเดียวคอร์คือมัลติเธรดปลอม โปรเซสเซอร์จะประมวลผลเพียงชิ้นส่วนของตรรกะในเวลาเดียวกัน แต่เธรดสลับค่อนข้างเร็วซึ่งดูเหมือนว่าหลายเธรดกำลังทำงาน "ในเวลาเดียวกัน" มัลติเธรดบนซีพียูมัลติคอร์เป็นมัลติเธรดจริง มันสามารถอนุญาตให้ตรรกะหลายเซ็กเมนต์ของคุณทำงานในเวลาเดียวกันและมัลติเธรด มันสามารถให้การเล่นอย่างเต็มที่กับข้อดีของซีพียูหลายคอร์เพื่อให้บรรลุเป้าหมายในการใช้ CPU อย่างเต็มที่
(2) ป้องกันการอุดตัน
จากมุมมองของประสิทธิภาพการทำงานของโปรแกรม CPU แบบคอร์เดียวจะไม่เพียง แต่ให้การเล่นเต็มรูปแบบกับข้อดีของการทำมัลติเธรด แต่จะลดประสิทธิภาพโดยรวมของโปรแกรมแทนที่จะใช้การทำมัลติเธรดบนซีพียูแบบคอร์เดียวจะทำให้เกิดการสลับบริบทของเธรด อย่างไรก็ตามเรายังคงต้องใช้มัลติเธรดกับซีพียูเดี่ยวเพื่อป้องกันการอุดตัน ลองจินตนาการว่าถ้า CPU แบบคอร์เดี่ยวใช้เธรดเดียวตราบใดที่เธรดถูกบล็อกตัวอย่างเช่นการอ่านข้อมูลบางอย่างจากระยะไกลเพียร์จะไม่ถูกส่งคืนเป็นเวลานานและไม่ได้ตั้งเวลาหมดเวลาโปรแกรมทั้งหมดของคุณจะหยุดทำงานก่อนที่ข้อมูลจะถูกส่งคืน มัลติเธรดสามารถป้องกันปัญหานี้ได้ หลายเธรดทำงานในเวลาเดียวกัน แม้ว่ารหัสของเธรดหนึ่งจะถูกบล็อกจากการอ่านข้อมูล แต่ก็จะไม่ส่งผลกระทบต่อการดำเนินงานอื่น ๆ
(3) ง่ายต่อการสร้างแบบจำลอง
นี่เป็นข้อได้เปรียบอีกประการหนึ่งที่ไม่ชัดเจน สมมติว่ามีงานขนาดใหญ่การเขียนโปรแกรมแบบเธรดเดี่ยวจากนั้นคุณต้องพิจารณามากและเป็นปัญหาในการสร้างโมเดลโปรแกรมทั้งหมด อย่างไรก็ตามหากคุณแบ่งงานใหญ่นี้ให้เป็นงานเล็ก ๆ หลายงานงาน B, Task C และ Task D สร้างโมเดลโปรแกรมแยกต่างหากและเรียกใช้งานเหล่านี้แยกต่างหากผ่านหลายเธรดมันจะง่ายกว่ามาก
2. วิธีการสร้างเธรด
ปัญหาที่พบบ่อยกว่าโดยทั่วไปคือสอง:
(1) สืบทอดคลาสเธรด
(2) ใช้อินเทอร์เฟซ Runnable
สำหรับสิ่งที่ดีกว่ามันไปโดยไม่บอกว่าหลังดีกว่าแน่นอนเพราะวิธีการใช้อินเทอร์เฟซมีความยืดหยุ่นมากกว่าวิธีการสืบทอดคลาสและยังสามารถลดการมีเพศสัมพันธ์ระหว่างโปรแกรม การเขียนโปรแกรมเชิงอินเตอร์เฟสเป็นแกนหลักของหลักการสำคัญหกประการของรูปแบบการออกแบบ
3. ความแตกต่างระหว่างวิธีการเริ่มต้น () และวิธีการเรียกใช้ ()
เฉพาะเมื่อเมธอด start () เรียกว่าจะแสดงลักษณะของมัลติเธรดหลายเธรดและรหัสในวิธีการเรียกใช้ () ของเธรดที่แตกต่างกันจะถูกดำเนินการสลับกัน หากคุณเพียงแค่เรียกเมธอด Run () รหัสจะถูกเรียกใช้งานแบบซิงโครนัส คุณต้องรอรหัสในเมธอด Run () ของหนึ่งเธรดที่จะดำเนินการก่อนที่เธรดอื่นสามารถเรียกใช้รหัสในวิธีการเรียกใช้ ()
4. ความแตกต่างระหว่างอินเทอร์เฟซที่เรียกใช้และอินเตอร์เฟส callable
มีคำถามที่ลึกซึ้งเล็กน้อยและยังแสดงให้เห็นถึงความรู้ที่เรียนรู้จากโปรแกรมเมอร์ Java
ค่าส่งคืนของวิธีการเรียกใช้ () ในอินเทอร์เฟซ runnable นั้นเป็นโมฆะและสิ่งที่ทำคือการเรียกใช้รหัสในวิธีการเรียกใช้ (); เมธอดการโทร () ในอินเทอร์เฟซ callable มีค่าส่งคืนซึ่งเป็นทั่วไปและสามารถใช้เพื่อให้ได้ผลลัพธ์ของการดำเนินการแบบอะซิงโครนัสร่วมกับ Future และ FutureTask
นี่เป็นคุณสมบัติที่มีประโยชน์มากเพราะเหตุผลสำคัญว่าทำไมมัลติเธรดจึงยากกว่าและซับซ้อนกว่าการทำเกลียวเดี่ยวคือมัลติเธรดเต็มไปด้วยสิ่งแปลกปลอม มีการดำเนินการเธรดบางอย่างหรือไม่? มีการดำเนินการเธรดมานานแค่ไหนแล้ว? ข้อมูลที่เราคาดหวังคือเมื่อมีการดำเนินการเธรดหรือไม่? ไม่ทราบว่าสิ่งที่เราทำได้คือรอให้งานมัลติเธรดนี้ถูกดำเนินการ Callable+Future/FutureTask สามารถรับผลลัพธ์ของการทำงานแบบมัลติเธรดและสามารถยกเลิกงานของเธรดได้เมื่อเวลารอนานเกินไปและไม่ได้รับข้อมูลที่ต้องการ มันมีประโยชน์จริงๆ
5. ความแตกต่างระหว่าง Cyclicbarrier และ Countdownlatch
ทั้งสองคลาสที่ดูคล้ายกันเล็กน้อยสามารถใช้เพื่อระบุว่ารหัสทำงาน ณ จุดหนึ่งภายใต้ java.util.concurrent ความแตกต่างระหว่างทั้งสองคือ:
(1) หลังจากเธรดของ cyclicbarrier ทำงานที่จุดหนึ่งเธรดจะหยุดทำงาน จนกว่าเธรดทั้งหมดมาถึงจุดนี้เธรดทั้งหมดจะไม่ทำงานอีกครั้ง Countdownlatch ไม่ใช่ หลังจากที่เธรดทำงาน ณ จุดหนึ่งมันจะให้ค่าที่แน่นอน -1 และเธรดยังคงทำงานต่อไป
(2) Cyclicbarrier สามารถทำให้เกิดงานได้เพียงหนึ่งเดียวเท่านั้น Countdownlatch สามารถทำให้เกิดงานได้หลายงาน
(3) CyclicBarrier สามารถนำกลับมาใช้ใหม่ได้นับถอยหลังไม่สามารถนำกลับมาใช้ใหม่ได้และค่าการนับคือ 0 จะไม่ถูกนำกลับมาใช้ใหม่และจะไม่ใช้ Countdownlatch อีกครั้ง
6. บทบาทของคำหลักที่ผันผวน
ปัญหาที่สำคัญมากคือโปรแกรมเมอร์ Java ทุกคนที่เรียนรู้และใช้มัลติเธรดต้องเชี่ยวชาญ สิ่งที่จำเป็นสำหรับการทำความเข้าใจบทบาทของคำหลักที่ผันผวนคือการเข้าใจโมเดลหน่วยความจำ Java ฉันจะไม่พูดถึงโมเดลหน่วยความจำ Java ที่นี่ คุณสามารถอ้างถึงจุดที่ 31 มีสองฟังก์ชั่นหลักของคำหลักที่ผันผวน:
(1) มัลติเธรดส่วนใหญ่หมุนรอบสองลักษณะของการมองเห็นและความเป็นอะตอม ตัวแปรที่แก้ไขโดยคำหลักที่ผันผวนทำให้มั่นใจได้ว่าการมองเห็นระหว่างหลายเธรดนั่นคือทุกครั้งที่อ่านตัวแปรผันผวนจะต้องเป็นข้อมูลล่าสุด
(2) การดำเนินการรหัสพื้นฐานไม่ง่ายเหมือนภาษาระดับสูงที่เราเห็น - โปรแกรม Java การดำเนินการของมันคือรหัส Java -> bytecode -> เรียกใช้รหัส C/C ++ ที่สอดคล้องกันตามรหัส bytecode -> C/C ++ ถูกรวบรวมเป็นภาษาแอสเซมบลี -> โต้ตอบกับวงจรฮาร์ดแวร์ ในความเป็นจริงเพื่อให้ได้ประสิทธิภาพที่ดีขึ้น JVM อาจจัดลำดับคำแนะนำใหม่และปัญหาที่ไม่คาดคิดอาจเกิดขึ้นภายใต้มัลติเธรด การใช้ความผันผวนจะห้ามการจัดลำดับความหมายใหม่ซึ่งแน่นอนว่าลดประสิทธิภาพของการดำเนินการรหัสในระดับหนึ่ง
จากมุมมองที่ใช้งานได้จริงบทบาทสำคัญของความผันผวนคือการรวมเข้ากับ CAS เพื่อให้แน่ใจว่าอะตอม สำหรับรายละเอียดคุณสามารถอ้างถึงคลาสภายใต้แพ็คเกจ java.util.concurrent.atomic เช่น Atomicinteger
7. ความปลอดภัยของด้ายคืออะไร
อีกคำถามทางทฤษฎีมีคำตอบมากมาย ฉันอยากจะให้สิ่งที่ฉันคิดว่าเป็นการส่วนตัวที่ดีที่สุด: หากรหัสของคุณสามารถได้รับผลลัพธ์เดียวกันเมื่อดำเนินการภายใต้มัลติเธรดและการเธรดเดี่ยวรหัสของคุณจะปลอดภัย
มีบางสิ่งที่ควรค่าแก่การกล่าวถึงเกี่ยวกับปัญหานี้นั่นคือมีหลายระดับของความปลอดภัยของด้าย:
(1) ไม่เปลี่ยนรูป
เช่นสตริงจำนวนเต็มยาว ฯลฯ พวกเขาเป็นประเภทสุดท้ายทั้งหมด ไม่มีเธรดที่สามารถเปลี่ยนค่าของพวกเขาได้ หากคุณต้องการเปลี่ยนพวกเขาคุณจะไม่สร้างใหม่ ดังนั้นวัตถุที่ไม่เปลี่ยนรูปเหล่านี้สามารถใช้โดยตรงในสภาพแวดล้อมแบบมัลติเธรดโดยไม่มีวิธีการซิงโครไนซ์ใด ๆ
(2) ความปลอดภัยของด้ายแน่นอน
โดยไม่คำนึงถึงสภาพแวดล้อมรันไทม์ผู้โทรไม่ต้องการมาตรการซิงโครไนซ์เพิ่มเติม ในการทำเช่นนี้คุณมักจะต้องจ่ายค่าใช้จ่ายเพิ่มเติมมากมาย ใน Java จริง ๆ แล้วไม่ใช่คลาสเธรดที่ปลอดภัย อย่างไรก็ตามยังมีคลาสที่มีความปลอดภัยอย่างแน่นอนเช่น copyonWriteArrayList และ copyOnWriteArraySet
(3) ความปลอดภัยของด้ายสัมพัทธ์
ความปลอดภัยของด้ายสัมพัทธ์เป็นสิ่งที่เรามักจะเรียกความปลอดภัยของด้าย ตัวอย่างเช่นเวกเตอร์เพิ่มและลบวิธีการคือการทำงานของอะตอมและจะไม่ถูกขัดจังหวะ แต่มัน จำกัด อยู่ที่สิ่งนี้ หากเธรดผ่านเวกเตอร์บางตัวจะมีการเพิ่มเธรดในเวลาเดียวกันจะมีการเกิดขึ้นพร้อมกันจะเกิดขึ้นใน 99% ของกรณีซึ่งเป็นกลไกที่ล้มเหลวอย่างรวดเร็ว
(4) เธรดไม่ปลอดภัย
ไม่มีอะไรจะพูดเกี่ยวกับเรื่องนี้ ArrayList, LinkedList, HashMap ฯลฯ ล้วนเป็นคลาสที่ไม่ใช่เธรด
8. วิธีรับไฟล์ Dread Dump ใน Java
สำหรับปัญหาต่าง ๆ เช่น Dead Loop, Deadlock, การปิดกั้น, การเปิดหน้าช้า ฯลฯ การกดปุ่ม Dread Dump เป็นวิธีที่ดีที่สุดในการแก้ปัญหา การถ่ายโอนข้อมูลด้ายที่เรียกว่าเป็นสแต็กเธรด มีสองขั้นตอนในการรับสแต็กเธรด:
(1) รับ PID ของเธรดคุณสามารถใช้คำสั่ง JPS และคุณยังสามารถใช้ PS -EF | grep java ในสภาพแวดล้อม Linux
(2) พิมพ์สแต็กเธรดคุณสามารถใช้คำสั่ง JSTACK PID และคุณยังสามารถใช้ Kill -3 PID ในสภาพแวดล้อม Linux
นอกจากนี้คลาสเธรดยังมีวิธี getStackTrace () ที่สามารถใช้เพื่อรับสแต็กเธรด นี่คือวิธีการอินสแตนซ์ดังนั้นวิธีนี้จะถูกผูกไว้กับอินสแตนซ์เธรดเฉพาะ ทุกครั้งที่คุณได้รับสแต็กที่ทำงานอยู่ในเธรดเฉพาะ
9. จะเกิดอะไรขึ้นถ้าเธรดมีข้อยกเว้นรันไทม์?
หากข้อยกเว้นนี้ไม่ถูกจับเธรดจะหยุดดำเนินการ อีกจุดสำคัญคือ: หากเธรดนี้มีจอภาพของวัตถุบางอย่างการตรวจสอบวัตถุจะถูกปล่อยออกมาทันที
10. วิธีแบ่งปันข้อมูลระหว่างสองเธรด
เพียงแบ่งปันวัตถุระหว่างเธรดแล้วกระตุ้นและรอผ่านการรอ/แจ้ง/แจ้งเตือน/แจ้งเตือนรอ/สัญญาณ/สัญญาณ ตัวอย่างเช่นการปิดกั้นการปิดกั้นคิวถูกออกแบบมาสำหรับการแบ่งปันข้อมูลระหว่างเธรด
11. ความแตกต่างระหว่างวิธีการนอนหลับกับวิธีการรอ
คำถามนี้ถูกถามบ่อยทั้งวิธีการนอนหลับและวิธีการรอสามารถใช้เพื่อเลิก CPU ในช่วงระยะเวลาหนึ่ง ความแตกต่างคือถ้าเธรดถือจอภาพของวัตถุวิธีการนอนหลับจะไม่ยอมแพ้การตรวจสอบของวัตถุนี้และวิธีการรอจะให้มอนิเตอร์ของวัตถุนี้
12. บทบาทของผู้ผลิตแบบจำลองผู้ผลิตคืออะไร?
คำถามนี้เป็นทฤษฎี แต่สำคัญ:
(1) ปรับปรุงประสิทธิภาพการดำเนินงานของระบบทั้งหมดโดยการปรับสมดุลกำลังการผลิตของผู้ผลิตและความสามารถในการบริโภคของผู้บริโภคซึ่งเป็นบทบาทที่สำคัญที่สุดของโมเดลผู้บริโภคผู้ผลิต
(2) decoupling นี่คือฟังก์ชั่นที่มาพร้อมกับผู้ผลิตและโมเดลผู้บริโภค Decoupling หมายความว่ามีการเชื่อมต่อน้อยลงระหว่างผู้ผลิตและผู้บริโภค ยิ่งมีการเชื่อมต่อน้อยลงเท่าไหร่พวกเขาก็สามารถพัฒนาได้ด้วยตนเองโดยไม่ได้รับข้อ จำกัด ร่วมกัน
13. การใช้ Threadlocal คืออะไร
พูดง่ายๆคือ Threadlocal เป็นการฝึกฝนการแลกเปลี่ยนพื้นที่สำหรับเวลา แต่ละเธรดจะรักษา ThreadLocal.ThreadLocalMap ที่ใช้โดยวิธีการเปิดที่อยู่เพื่อแยกข้อมูลและไม่แบ่งปันข้อมูลดังนั้นจึงไม่มีปัญหาด้านความปลอดภัยของเธรด
14. ทำไมต้องรอ () และแจ้งให้ทราบ ()/notifyall () วิธีการในบล็อกการซิงโครไนซ์
สิ่งนี้ถูกบังคับโดย JDK วิธีการรอ () และแจ้ง ()/notifyall () วิธีการจะต้องได้รับการล็อคของวัตถุก่อนโทร
15. วิธีการรอคอย () และการแจ้งเตือน ()/notifyall () คืออะไรเมื่อละทิ้งการตรวจสอบวัตถุ
ความแตกต่างระหว่างเมธอดรอ () และวิธีการแจ้งเตือน ()/notifyall () เมื่อให้การตรวจสอบวัตถุคือวิธีการรอ () จะปล่อยการตรวจสอบวัตถุทันทีในขณะที่วิธีการแจ้งเตือน ()/notifyall () จะรอรหัสที่เหลือของเธรดที่จะดำเนินการก่อนที่จะทำการตรวจสอบวัตถุ
16. ทำไมต้องใช้พูลเธรด
หลีกเลี่ยงการสร้างและการทำลายเธรดบ่อยครั้งเพื่อให้ได้การนำวัตถุเธรดมาใช้ซ้ำ นอกจากนี้การใช้พูลเธรดยังสามารถควบคุมจำนวนการเกิดขึ้นพร้อมกันได้อย่างยืดหยุ่นตามโครงการ
17. วิธีตรวจสอบว่าเธรดมีการตรวจสอบวัตถุ
ฉันยังเห็นคำถามสัมภาษณ์แบบมัลติเธรดบนอินเทอร์เน็ตเพื่อทราบว่ามีวิธีการตรวจสอบว่าเธรดมีการตรวจสอบวัตถุ: คลาสเธรดให้วิธี Holdslock (Object OBJ) ซึ่งจะส่งคืนจริงหรือไม่หากจอภาพของ Objj Obj ถูกจัดขึ้นโดยเธรด โปรดทราบว่านี่เป็นวิธีการคงที่ซึ่งหมายความว่า "เธรดบางอย่าง" หมายถึงเธรดปัจจุบัน
18. ความแตกต่างระหว่างการซิงโครไนซ์และ reentrantlock
ซิงโครไนซ์เป็นคำหลักเดียวกับที่อื่น ๆ สำหรับและในขณะที่และ reentrantlock เป็นคลาสซึ่งเป็นความแตกต่างที่สำคัญระหว่างทั้งสอง เนื่องจาก Reentrantlock เป็นคลาสจึงมีคุณสมบัติที่ยืดหยุ่นมากขึ้นเรื่อย ๆ มากกว่าการซิงโครไนซ์ซึ่งสามารถสืบทอดได้มีวิธีการและมีตัวแปรคลาสต่างๆ ความสามารถในการปรับขนาดของ reentrantlock ได้มากกว่าการซิงโครไนซ์จะสะท้อนให้เห็นในหลาย ๆ จุด:
(1) reentrantlock สามารถกำหนดเวลารอการล็อคได้ดังนั้นหลีกเลี่ยงการหยุดชะงัก
(2) reentrantlock สามารถรับข้อมูลล็อคต่างๆได้
(3) Reentrantlock สามารถใช้การแจ้งเตือนแบบหลายช่องทางได้อย่างยืดหยุ่น
นอกจากนี้กลไกการล็อคของทั้งสองนั้นแตกต่างกันจริง ๆ reentrantlock พื้นฐานเรียกวิธีการอุทยานของ Unsafe เพื่อล็อคและการดำเนินการที่ซิงโครไนซ์ควรเป็นคำทำเครื่องหมายในส่วนหัวของวัตถุฉันไม่สามารถแน่ใจได้
19. การพร้อมกันของการเกิดขึ้นพร้อมกันคืออะไร
การเกิดขึ้นพร้อมกันของการเกิดขึ้นพร้อมกันคือขนาดของเซ็กเมนต์ซึ่งเป็น 16 โดยค่าเริ่มต้นซึ่งหมายความว่าส่วนใหญ่ 16 เธรดสามารถทำงานร่วมกันได้ในเวลาเดียวกัน นี่เป็นข้อได้เปรียบที่ยิ่งใหญ่ที่สุดของการเกิดขึ้นพร้อมกันในการแฮช ไม่ว่าในกรณีใด Hashtable สามารถมีสองเธรดในเวลาเดียวกันได้รับข้อมูลใน Hashtable หรือไม่?
20. ReadWriteLock คืออะไร
ก่อนอื่นมาทำให้ชัดเจนว่าไม่ใช่ว่า reentrantlock นั้นไม่ดีมันเป็นเพียงแค่ reentrantlock นั้นถูก จำกัด ในบางครั้ง หากใช้ reentrantlock อาจเป็นการป้องกันความไม่สอดคล้องกันของข้อมูลที่เกิดจากเธรดข้อมูลการเขียนและข้อมูลการอ่านเธรด B อย่างไรก็ตามด้วยวิธีนี้หากเธรด C อ่านข้อมูลและเธรด D คือการอ่านข้อมูลการอ่านข้อมูลจะไม่เปลี่ยนแปลงข้อมูล ไม่จำเป็นต้องล็อค แต่ก็ยังล็อคอยู่ซึ่งจะช่วยลดประสิทธิภาพของโปรแกรม
ด้วยเหตุนี้ ReadwriteLock Read-Write จึงเกิดมา ReadWriteLock เป็นอินเทอร์เฟซล็อคอ่าน-เขียน ReentRantReadWriteLock เป็นการใช้งานที่เป็นรูปธรรมของอินเทอร์เฟซ ReadWriteLock ซึ่งตระหนักถึงการแยกการอ่านและการเขียน ล็อคอ่านจะถูกแชร์และล็อคการเขียนเป็นเอกสิทธิ์ อ่านและอ่านและอ่านจะไม่เป็นเอกสิทธิ์เฉพาะบุคคล เฉพาะการอ่านและเขียนเขียนและอ่านเขียนและเขียนจะเป็นพิเศษร่วมกันปรับปรุงประสิทธิภาพของการอ่านและการเขียน
21. FutureTask คืออะไร
สิ่งนี้ถูกกล่าวถึงก่อนหน้านี้ FutureTask แสดงถึงงานการดำเนินการแบบอะซิงโครนัส คลาสการใช้งานที่เฉพาะเจาะจงของ callable สามารถส่งผ่านไปยัง FutureTask ซึ่งสามารถรอผลลัพธ์ของการดำเนินการแบบอะซิงโครนัสนี้เพื่อให้ได้มาพิจารณาว่ามันเสร็จสมบูรณ์หรือไม่และยกเลิกงาน แน่นอนเนื่องจาก FutureTask ยังเป็นคลาสการใช้งานของอินเทอร์เฟซ Runnable จึงสามารถวาง FutureTask ในพูลเธรดได้
22. วิธีค้นหาเธรดที่ใช้ CPU ที่ยาวที่สุดในสภาพแวดล้อม Linux
นี่เป็นปัญหาที่ใช้งานได้จริงมากขึ้นและฉันคิดว่าปัญหานี้ค่อนข้างมีความหมาย คุณสามารถทำได้:
(1) รับ PID ของโครงการ JPS หรือ PS -EF | Grep Java ซึ่งได้รับการกล่าวถึงก่อนหน้านี้
(2) top -h -p pid ไม่สามารถเปลี่ยนแปลงคำสั่งซื้อได้
สิ่งนี้จะพิมพ์เปอร์เซ็นต์ของเวลา CPU ที่โครงการปัจจุบันใช้สำหรับแต่ละเธรด โปรดทราบว่าที่นี่คือ LWP ซึ่งเป็นหมายเลขเธรดของเธรดเนทีฟของระบบปฏิบัติการ สมุดบันทึกของฉันไม่ได้ปรับใช้โครงการ Java ในสภาพแวดล้อม Linux ดังนั้นจึงไม่มีวิธีที่จะถ่ายภาพหน้าจอและการสาธิต หาก บริษัท กำลังปรับใช้โครงการโดยใช้สภาพแวดล้อม Linux คุณสามารถลองได้
การใช้ "Top -h -P -P PID" + "JPS PID" สามารถค้นหาสแต็กเธรดที่ใช้งาน CPU สูงได้อย่างง่ายดายดังนั้นการวางเหตุผลสำหรับการเข้าพักของ CPU สูงซึ่งโดยทั่วไปเกิดจากการดำเนินการรหัสที่ไม่เหมาะสมซึ่งนำไปสู่การวนซ้ำ
ในที่สุดให้ฉันพูดถึงว่า LWP เล่นกับ "Top -H -P -P PID" เป็นทศนิยมและหมายเลขเธรดท้องถิ่นที่เล่นกับ "JPS PID" คือเลขฐานสิบหก หลังการแปลงคุณสามารถค้นหาสแต็กเธรดปัจจุบันที่ใช้งาน CPU สูง
23. การเขียนโปรแกรม Java เขียนโปรแกรมที่จะทำให้เกิดการหยุดชะงัก
ฉันเห็นคำถามนี้เป็นครั้งแรกและคิดว่ามันเป็นคำถามที่ดีมาก หลายคนรู้ว่าการหยุดชะงักเป็นอย่างไร: เธรด A และ Thread B กำลังรอล็อคของกันและกันเพื่อให้เกิดการวนซ้ำที่ไม่มีที่สิ้นสุดเพื่อดำเนินการต่อโปรแกรมต่อไป แน่นอนว่ามัน จำกัด เฉพาะสิ่งนี้ หากคุณถามวิธีการเขียนโปรแกรมหยุดชะงักคุณจะไม่ทราบ ในการกล่าวอย่างตรงไปตรงมาคุณไม่เข้าใจว่าการหยุดชะงักคืออะไร หากคุณเข้าใจทฤษฎีคุณจะทำ โดยทั่วไปคุณไม่เห็นปัญหาการหยุดชะงักในทางปฏิบัติ
เพื่อให้เข้าใจอย่างแท้จริงว่าการหยุดชะงักคืออะไรคำถามนี้ไม่ใช่เรื่องยากมีไม่กี่ขั้นตอน:
(1) สองเธรดถือวัตถุสองวัตถุ: Lock1 และ Lock2 ตามลำดับ ล็อคทั้งสองนี้ทำหน้าที่เป็นล็อคสำหรับบล็อกรหัสแบบซิงโครนัส
(2) ในวิธีการเรียกใช้ () ของเธรด 1 บล็อกรหัสการซิงโครไนซ์จะได้รับการล็อควัตถุของ Lock1, thread.sleep (xxx) ก่อนเวลาไม่ใช้เวลามากเกินไป 50 มิลลิวินาทีเกือบจะเหมือนกันแล้วรับล็อควัตถุของ Lock2 สิ่งนี้ส่วนใหญ่ทำเพื่อป้องกันเธรด 1 จากการล็อควัตถุอย่างต่อเนื่องของวัตถุสองวัตถุ: Lock1 และ Lock2
(3) การเรียกใช้เธรด 2) (ในวิธีการบล็อกรหัสการซิงโครไนซ์แรกจะได้รับ Object Lock2 ก่อนจากนั้นจะได้รับ Object Lock1 แน่นอนว่า Object Lock1 จะถูกจัดขึ้นโดยเธรด 1 Lock และเธรด 2 ต้องรอเธรด 1 เพื่อปล่อย Object Lock1
ด้วยวิธีนี้หลังจากเธรด 1 "sleeps" และ Thread 2 ได้รับ Object Lock2 เธรด 1 พยายามที่จะได้รับ Object Lock2 ในเวลานี้และถูกบล็อก ในเวลานี้มีการหยุดชะงัก ฉันจะไม่เขียนรหัสอีกต่อไปมันใช้พื้นที่มาก Java MultithReading 7: Deadlock บทความนี้มีการใช้รหัสการใช้งานของขั้นตอนข้างต้น
24. วิธีปลุกด้ายบล็อก
หากบล็อกเธรดเนื่องจากการโทรรอ (), sleep () หรือเข้าร่วม () วิธีการมันสามารถขัดจังหวะเธรดและตื่นขึ้นมาโดยการขว้าง InterruptedException; หากเธรดเผชิญหน้ากับการอุดตันของ IO มันไม่มีอำนาจเนื่องจาก IO ถูกนำไปใช้โดยระบบปฏิบัติการและรหัส Java ไม่สามารถติดต่อระบบปฏิบัติการโดยตรงได้
25. วัตถุที่ไม่เปลี่ยนรูปช่วยได้อย่างไรช่วยมัลติเธรด
ปัญหาที่กล่าวถึงข้างต้นคือวัตถุที่ไม่เปลี่ยนรูปตรวจสอบให้แน่ใจว่าการมองเห็นหน่วยความจำของวัตถุและไม่จำเป็นต้องมีการซิงโครไนซ์เพิ่มเติมเพื่ออ่านวัตถุที่ไม่เปลี่ยนรูปซึ่งปรับปรุงประสิทธิภาพการดำเนินการของรหัส
26. การสลับบริบทแบบมัลติเธรดคืออะไร
การสลับบริบทแบบมัลติเธรดหมายถึงกระบวนการสลับการควบคุม CPU จากเธรดที่ทำงานอยู่หนึ่งไปยังเธรดอื่นพร้อมและรอสิทธิ์การดำเนินการ CPU ที่จะได้รับ
27. หากคิวพูลเธรดเต็มเมื่อคุณส่งงานจะเกิดอะไรขึ้นในเวลานี้
หากคุณใช้ LinkedBlockingQueue นั่นคือคิวที่ไม่มีขอบเขตมันไม่สำคัญ เพิ่มงานต่อไปยังคิวการปิดกั้นและรอการดำเนินการเพราะ LinkedBlockingQueue สามารถถือว่าเป็นคิวที่ไม่มีที่สิ้นสุดและสามารถจัดเก็บงานได้อย่างไม่สิ้นสุด หากคุณใช้คิวที่มีขอบเขตเช่น ArrayblockingQueue งานจะถูกเพิ่มเข้าไปใน ArrayBlockingQueue ก่อน หาก arrayblockingqueue เต็มรูปแบบการปฏิเสธ ExhedExecutionHandler จะใช้นโยบายการปฏิเสธเพื่อจัดการงานเต็มรูปแบบและค่าเริ่มต้นคือการทำแท้ง
28. อัลกอริทึมการตั้งเวลาของเธรดใช้ใน Java คืออะไร?
สไตล์การยึดเอาเสีย หลังจากเธรดใช้ CPU ระบบปฏิบัติการจะคำนวณลำดับความสำคัญทั้งหมดตามข้อมูลเช่นลำดับความสำคัญของเธรดความหิวของเธรด ฯลฯ และจัดสรรชิ้นส่วนต่อไปเป็นเธรดสำหรับการดำเนินการ
29. ฟังก์ชั่นของ Thread.sleep (0) คืออะไร
คำถามนี้เกี่ยวข้องกับคำถามข้างต้นและฉันทั้งหมดอยู่ด้วยกัน เนื่องจาก Java ใช้อัลกอริทึมการกำหนดตารางเวลาแบบ preemptive เธรดจึงอาจเกิดขึ้นได้ว่าเธรดมักจะได้รับการควบคุม CPU เพื่อให้บางเธรดที่มีลำดับความสำคัญค่อนข้างต่ำเพื่อให้ได้การควบคุม CPU, thread.sleep (0) สามารถใช้เพื่อกระตุ้นระบบปฏิบัติการจัดสรรเวลาซึ่งยังเป็นการดำเนินการเพื่อปรับสมดุลการควบคุม CPU
30. สปินคืออะไร
รหัสที่ซิงโครไนซ์จำนวนมากเป็นเพียงรหัสที่ง่ายมากและเวลาดำเนินการเร็วมาก การล็อคเธรดที่รออยู่ในเวลานี้อาจเป็นการดำเนินการที่ไม่คุ้มค่าเนื่องจากการปิดกั้นเธรดเกี่ยวข้องกับการสลับสถานะผู้ใช้และรัฐเคอร์เนล เนื่องจากรหัสที่ซิงโครไนซ์ดำเนินการอย่างรวดเร็วคุณอาจปล่อยให้เธรดรอการล็อคไม่ถูกบล็อก แต่แทนที่จะทำลูปยุ่งที่ขอบเขตของการซิงโครไนซ์แทน นี่คือสปิน หากคุณทำลูปที่ยุ่งหลายครั้งและพบว่าไม่ได้รับการล็อคแล้วบล็อกมันอาจเป็นกลยุทธ์ที่ดีกว่า
31. โมเดลหน่วยความจำ Java คืออะไร
โมเดลหน่วยความจำ Java กำหนดข้อกำหนดสำหรับการเข้าถึงหลายเธรดไปยังหน่วยความจำ Java โมเดลหน่วยความจำ Java ต้องได้รับการอธิบายอย่างเต็มที่ แต่ฉันไม่สามารถอธิบายได้อย่างชัดเจนในสองสามประโยคที่นี่ ให้ฉันสรุปมันสั้น ๆ
หลายส่วนของโมเดลหน่วยความจำ Java:
(1) โมเดลหน่วยความจำ Java แบ่งหน่วยความจำออกเป็นหน่วยความจำหลักและหน่วยความจำที่ใช้งานได้ สถานะของคลาสนั่นคือตัวแปรที่ใช้ร่วมกันระหว่างคลาสจะถูกเก็บไว้ในหน่วยความจำหลัก ทุกครั้งที่เธรด Java ใช้ตัวแปรเหล่านี้ในหน่วยความจำหลักมันจะอ่านตัวแปรในหน่วยความจำหลักและปล่อยให้มันมีอยู่ในหน่วยความจำการทำงานของตัวเอง เมื่อเรียกใช้รหัสเธรดของตัวเองจะใช้ตัวแปรเหล่านี้และทำงานในหน่วยความจำการทำงานของตัวเอง หลังจากดำเนินการรหัสเธรดแล้วค่าล่าสุดจะได้รับการอัปเดตเป็นหน่วยความจำหลัก
(2) การดำเนินการอะตอมหลายครั้งถูกกำหนดให้ใช้งานตัวแปรในหน่วยความจำหลักและหน่วยความจำในการทำงาน
(3) กำหนดกฎสำหรับการใช้ตัวแปรระเหยง่าย
(4) เกิดขึ้นก่อนหน้านั่นคือหลักการของการเกิดขึ้นครั้งแรกกำหนดกฎบางอย่างที่การดำเนินการจะต้องเกิดขึ้นก่อนในการดำเนินการ B ตัวอย่างเช่นรหัสที่อยู่ด้านหน้าของการไหลของการควบคุมในเธรดเดียวกันจะต้องเกิดขึ้นก่อนในรหัสที่อยู่ด้านหลังโฟลว์การควบคุม หากรหัสบางส่วนไม่สอดคล้องกับกฎทั้งหมดก่อนหน้านี้รหัสชิ้นนี้จะต้องเป็นเธรด-ไม่ปลอดภัย
32. CAS คืออะไร
CAS ชื่อเต็มเปรียบเทียบและตั้งค่าคือการเปรียบเทียบ สมมติว่ามีสามตัวถูกดำเนินการ: ค่าหน่วยความจำ V, ค่าที่คาดหวังเก่า a, ค่า B ที่จะแก้ไข ถ้าหากค่าที่คาดหวัง A และค่าหน่วยความจำ V เหมือนกันค่าหน่วยความจำจะถูกแก้ไขเป็น B และส่งคืนจริงมิฉะนั้นจะไม่มีอะไรจะทำและจะส่งคืน แน่นอน CAS จะต้องร่วมมือกับตัวแปรผันผวนเพื่อให้แน่ใจว่าตัวแปรที่ได้รับในแต่ละครั้งเป็นค่าล่าสุดในหน่วยความจำหลัก มิฉะนั้นค่าที่คาดหวังเก่า A จะเป็นค่า A ที่จะไม่เปลี่ยนแปลงสำหรับเธรด ตราบใดที่การดำเนินการ CAS บางอย่างล้มเหลวก็จะไม่ประสบความสำเร็จ
33. การล็อคในแง่ดีและการล็อคในแง่ร้ายคืออะไร
(1) การล็อคในแง่ดี: เช่นเดียวกับชื่อมันเป็นแง่ดีเกี่ยวกับปัญหาความปลอดภัยของเธรดที่เกิดจากการดำเนินการพร้อมกัน Optimistic Lock เชื่อว่าการแข่งขันไม่ได้เกิดขึ้นเสมอไปดังนั้นจึงไม่จำเป็นต้องถือการล็อคและจะเปรียบเทียบ - ตั้งค่าการกระทำทั้งสองนี้เป็นการดำเนินการอะตอมเพื่อพยายามปรับเปลี่ยนตัวแปรในหน่วยความจำ หากล้มเหลวก็หมายถึงความขัดแย้งเกิดขึ้นและควรมีตรรกะการลองใหม่ที่สอดคล้องกัน
(2) ล็อคในแง่ร้าย: เช่นเดียวกับชื่อมันเป็นแง่ร้ายเกี่ยวกับปัญหาด้านความปลอดภัยของด้ายที่เกิดจากการดำเนินการพร้อมกัน ล็อคในแง่ร้ายเชื่อว่าการแข่งขันจะเกิดขึ้นเสมอ ดังนั้นทุกครั้งที่มีการดำเนินการทรัพยากรจะมีการล็อคแบบพิเศษเช่นเดียวกับการซิงโครไนซ์ไม่ว่าจะถูกล็อคโดยตรงหรือไม่และทรัพยากรจะดำเนินการ
34. AQS คืออะไร
มาพูดคุยสั้น ๆ เกี่ยวกับ AQS ชื่อเต็มของ AQS คือ abstractqueuedsychronizer มันควรจะเป็นคิวนามสกุลนามธรรมเมื่อแปล
หากพื้นฐานของ java.util.concurrent คือ Cas ดังนั้น AQS เป็นแกนหลักของแพ็คเกจพร้อมกัน Java ทั้งหมดและ reentrantlock, Countdownlatch, Semaphore ฯลฯ ทั้งหมดใช้มัน AQS เชื่อมต่อรายการทั้งหมดในรูปแบบของคิวสองทิศทาง ตัวอย่างเช่น reentrantlock เธรดที่รอทั้งหมดจะถูกวางไว้ในรายการและเชื่อมต่อกับคิวสองทิศทาง หากเธรดก่อนหน้านี้ใช้ reentrantlock รายการแรกของคิวสองทิศทางจะเริ่มทำงานจริง
AQS กำหนดการดำเนินการทั้งหมดในคิวแบบสองทิศทาง แต่จะเปิดเฉพาะวิธีการ trylock และ tryrelease สำหรับนักพัฒนาที่จะใช้ นักพัฒนาสามารถเขียนวิธี trylock และ tryrelease ใหม่ตามการใช้งานของตนเองเพื่อใช้ฟังก์ชั่นการทำงานร่วมกันของตนเอง
35. ความปลอดภัยด้ายของโหมดซิงเกิลตัน
ปัญหาความคิดโบราณสิ่งแรกที่จะพูดคือความปลอดภัยของด้ายของรูปแบบ Singleton หมายความว่า: อินสแตนซ์ของคลาสบางชั้นจะถูกสร้างขึ้นเพียงครั้งเดียวในสภาพแวดล้อมแบบมัลติเธรด มีหลายวิธีในการเขียนรูปแบบ Singleton ให้ฉันสรุป:
(1) การเขียนรูปแบบ Singleton ของ Hungry Man: Safety Thread
(2) การเขียนรูปแบบ Lazy Singleton: ไม่ปลอดภัย
(3) เขียนโหมด Singleton ของ Double Check Lock: Thread Safety
36. ฟังก์ชั่นของเซมาฟอร์คืออะไร
Semaphore เป็นสัญญาณสัญญาณและฟังก์ชั่นของมันคือการ จำกัด จำนวนของการเกิดขึ้นพร้อมกันในบล็อกรหัสที่แน่นอน Semaphore มีตัวสร้างที่สามารถผ่านจำนวนเต็ม in int ซึ่งระบุว่ามีเพียงเธรด N เท่านั้นที่สามารถเข้าถึงรหัสบางส่วน หากเกิน n โปรดรอจนกว่าเธรดจะเสร็จสิ้นบล็อกรหัสและป้อนเธรดถัดไป จากนี้เราจะเห็นได้ว่าหากจำนวนเต็ม int n = 1 ผ่านในคอนสตรัคเตอร์สัญญาณจะเทียบเท่ากับการกลายเป็นซิงโครไนซ์
37. มีเพียงคำสั่งเดียว "การนับคืน" ในวิธีการแฮชแต้มขนาด () ดังนั้นทำไมคุณยังต้องซิงโครไนซ์?
นี่เป็นความสับสนที่ฉันเคยมีมาก่อนและฉันสงสัยว่าคุณเคยคิดเกี่ยวกับคำถามนี้หรือไม่ หากมีหลายข้อความในวิธีการและพวกเขาทั้งหมดทำงานอยู่ในตัวแปรคลาสเดียวกันถ้าคุณไม่เพิ่มล็อคในสภาพแวดล้อมแบบมัลติเธรดก็จะทำให้เกิดปัญหาด้านความปลอดภัยของเธรดได้อย่างหลีกเลี่ยงไม่ได้ นี่เป็นเรื่องง่ายที่จะเข้าใจ แต่วิธีการขนาด () มีเพียงคำสั่งเดียวเท่านั้นดังนั้นทำไมคุณยังต้องเพิ่มล็อค?
เกี่ยวกับปัญหานี้ฉันเข้าใจผ่านการทำงานและการศึกษาอย่างช้าๆและมีสองเหตุผลหลัก:
(1) มีเพียงเธรดเดียวเท่านั้นที่สามารถเรียกใช้วิธีการซิงโครไนซ์ของคลาสคงที่ในเวลาเดียวกัน แต่สำหรับวิธีการแบบอะซิงโครนัสของคลาสเธรดหลายตัวสามารถเข้าถึงได้ในเวลาเดียวกัน ดังนั้นจึงมีปัญหา บางทีเธรด A กำลังเพิ่มข้อมูลเมื่อดำเนินการวิธีการที่วางของ Hashtable และ Thread B สามารถเรียกใช้เมธอดขนาด () ตามปกติเพื่ออ่านจำนวนองค์ประกอบปัจจุบันในแฮชแต้ม การอ่านค่าอาจไม่ใช่ล่าสุด บางทีเธรด A ได้เพิ่มข้อมูล แต่ไม่มีขนาด ++ เธรด B ได้อ่านขนาดแล้ว ดังนั้นสำหรับเธรด B การอ่านขนาดจะต้องไม่ถูกต้อง หลังจากเพิ่มวิธีการซิงโครไนซ์กับขนาด () หมายความว่าเธรด B เรียกเมธอดขนาด () หลังจากเธรดการเรียกวิธีการใส่ซึ่งช่วยให้มั่นใจในความปลอดภัยของเธรด
(2) CPU ดำเนินการรหัส แต่ไม่ใช่รหัส Java สิ่งนี้สำคัญมากและคุณต้องจำไว้ ในที่สุดรหัส Java จะถูกแปลเป็นรหัสแอสเซมบลีเพื่อดำเนินการและรหัสแอสเซมบลีเป็นรหัสที่สามารถโต้ตอบกับวงจรฮาร์ดแวร์ได้อย่างแท้จริง แม้ว่าคุณจะเห็นว่ามีรหัส Java เพียงบรรทัดเดียวเท่านั้นและแม้ว่าคุณจะเห็นว่ารหัส Java ถูกรวบรวม แต่ก็มีการสร้างไบต์เพียงบรรทัดเดียว แต่ก็ไม่ได้หมายความว่าสำหรับเลเยอร์พื้นฐานมีการดำเนินการเพียงครั้งเดียวสำหรับคำสั่งนี้ ประโยค "การนับผลตอบแทน" สมมติว่ามันถูกแปลเป็นสามคำสั่งประกอบเพื่อดำเนินการและเป็นไปได้ทั้งหมดที่เธรดจะสลับหลังจากประโยคแรกถูกเรียกใช้งาน
38. เธรดใดเป็นตัวสร้างของคลาสเธรดและบล็อกคงที่เรียกโดยเธรดใด
นี่เป็นคำถามที่ยุ่งยากและมีไหวพริบมาก โปรดจำไว้ว่า: ตัวสร้างและบล็อกคงที่ของคลาสเธรดถูกเรียกโดยเธรดที่มีคลาสเธรดใหม่อยู่และรหัสในวิธีการเรียกใช้เรียกโดยเธรดเอง
หากคำสั่งข้างต้นทำให้คุณสับสนให้ฉันยกตัวอย่างให้คุณสมมติว่า Thread1 ใหม่อยู่ใน Thread2 และ Thread2 ใหม่อยู่ในฟังก์ชั่นหลักแล้ว:
(1) ตัวสร้างและบล็อกคงที่ของ Thread2 เรียกว่าโดยเธรดหลักและวิธีการ Run () ของ Thread2 นั้นเรียกโดย Thread2 เอง
(2) ตัวสร้างและบล็อกคงที่ของ Thread1 เรียกว่า Thread2 และวิธีการเรียกใช้ () ของ Thread1 เรียกว่า Thread1 เอง
39. ตัวเลือกใดที่ดีกว่าระหว่างวิธีการซิงโครไนซ์และบล็อกการซิงโครไนซ์?
ซิงโครไนซ์บล็อกซึ่งหมายความว่ารหัสนอกบล็อกการซิงโครไนซ์จะดำเนินการแบบอะซิงโครนัสซึ่งช่วยปรับปรุงประสิทธิภาพของรหัสที่มีประสิทธิภาพมากกว่าการซิงโครไนซ์วิธีทั้งหมด โปรดทราบหลักการหนึ่ง: ช่วงการซิงโครไนซ์น้อยลง
ดีกว่า.
ด้วยบทความนี้ฉันอยากจะพูดถึงว่าถึงแม้ว่าช่วงการซิงโครไนซ์ที่เล็กกว่านั้นจะดีกว่า แต่ก็ยังมีวิธีการเพิ่มประสิทธิภาพที่เรียกว่าล็อคความหยาบในเครื่องเสมือน Java ซึ่งจะเพิ่มช่วงการซิงโครไนซ์ สิ่งนี้มีประโยชน์ ตัวอย่างเช่น StringBuffer เป็นคลาสเธรดที่ปลอดภัย โดยธรรมชาติวิธีการที่ใช้กันมากที่สุด () เป็นวิธีการซิงโครไนซ์ เมื่อเราเขียนโค้ดเราจะผนวกสตริงซ้ำ ๆ ซึ่งหมายถึงการล็อคซ้ำ ๆ -> การปลดล็อคซึ่งไม่ดีต่อประสิทธิภาพเพราะมันหมายความว่าเครื่องเสมือน Java ต้องสลับระหว่างสถานะเคอร์เนลและสถานะผู้ใช้ซ้ำ ๆ ซ้ำ ๆ ดังนั้น Java Virtual Machine จึงทำการดำเนินการล็อคระทึกขวัญบนรหัสที่เรียกโดยวิธีการหลายภาคผนวกขยายการดำเนินการต่อท้ายหลายครั้งไปยังส่วนหัวและหางของวิธีการผนวกและเปลี่ยนเป็นบล็อกการซิงโครไนซ์ขนาดใหญ่ สิ่งนี้จะช่วยลดจำนวนการล็อค-> การปลดล็อคเวลาปรับปรุงประสิทธิภาพของการดำเนินการรหัสได้อย่างมีประสิทธิภาพ
40. จะใช้พูลเธรดสำหรับธุรกิจที่มีเวลาทำงานพร้อมกันและงานสั้น ๆ ได้อย่างไร? วิธีการใช้พูลเธรดสำหรับธุรกิจที่มีเวลาทำงานร่วมกันต่ำและงานที่ยาวนาน? วิธีการใช้พูลเธรดสำหรับธุรกิจที่มี เวลาดำเนินการ พร้อมกันและ การให้บริการที่ยาวนาน
นี่เป็นคำถามที่ฉันเห็นในเว็บไซต์การเขียนโปรแกรมพร้อมกัน ฉันใส่คำถามนี้ครั้งสุดท้ายและหวังว่าทุกคนจะได้เห็นและคิดเกี่ยวกับมันเพราะคำถามนี้ดีมากใช้งานได้จริงและเป็นมืออาชีพมาก เกี่ยวกับปัญหานี้ความเห็นส่วนตัวของฉันคือ:
(1) เวลาดำเนินการพร้อมกันสูงและเวลาการดำเนินการสั้น
(2)并发不高、任务执行时间长的业务要区分开看:
a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的线程数目,让CPU处理更多的业务
b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换
(3)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。
Java线程阻塞(Blocked)的类型:
调用sleep函数进入睡眠状态,Thread.sleep(1000)或者TimeUnit.SECONDS.sleep(1),sleep不会释放锁。
等待(wait)某个事件,分为两种,(wait,notify,notifyAll),(await, signal,signalAll) ,后面会详细介绍。wait和await会释放锁,且必须在获取到锁的环境才能调用。
等待锁,synchronized和lock环境中,锁已经被别的线程拿走,等待获取锁。
IO阻塞(Blocked),比如网络等待,文件打开,控制台读取。System.in.read()。