มัลติเธรดใน Java
Java Virtual Machine รองรับการประมวลผลแบบขนาน การคำนวณทั้งหมดสามารถทำได้ในบริบทของหนึ่งเธรดหรือมากกว่านั้น เราสามารถตั้งค่าการเข้าถึงทรัพยากรหรืออ็อบเจกต์เดียวกันสำหรับหลายเธรดได้อย่างง่ายดาย รวมทั้งตั้งค่าเธรดเพื่อเรียกใช้โค้ดบล็อกเดียว
นักพัฒนาจำเป็นต้องซิงโครไนซ์งานกับเธรดระหว่างการดำเนินการอ่านและเขียนสำหรับทรัพยากรที่มีการจัดสรรหลายเธรดให้
สิ่งสำคัญคือในขณะที่เข้าถึงทรัพยากร คุณต้องมีข้อมูลล่าสุด เพื่อให้เธรดอื่นสามารถเปลี่ยนแปลงได้ และคุณได้รับข้อมูลที่อัปเดตที่สุด แม้ว่าเราจะยกตัวอย่างบัญชีธนาคาร แต่คุณไม่สามารถใช้มันได้จนกว่าจะมีเงินเข้ามา ดังนั้นสิ่งสำคัญคือต้องมีข้อมูลที่เป็นปัจจุบันอยู่เสมอ Java มีคลาสพิเศษสำหรับการซิงโครไนซ์และจัดการเธรด
วัตถุเธรด
ทุกอย่างเริ่มต้นด้วยเธรดหลัก (หลัก) นั่นคืออย่างน้อยโปรแกรมของคุณมีหนึ่งเธรดที่ทำงานอยู่ เธรดหลักสามารถสร้างเธรดอื่นๆ โดยใช้CallableหรือRunnable การสร้างแตกต่างเฉพาะในผลลัพธ์ที่ส่งคืนRunnableไม่ส่งคืนผลลัพธ์และไม่สามารถโยนข้อยกเว้นที่ตรวจสอบได้ ดังนั้น คุณจะได้รับโอกาสที่ดีในการสร้างงานที่มีประสิทธิภาพกับไฟล์ แต่สิ่งนี้อันตรายมากและคุณต้องระวัง
นอกจากนี้ยังสามารถกำหนดเวลาการทำงานของเธรดบนคอร์ CPU แยกต่างหาก ระบบสามารถย้ายระหว่างเธรดได้อย่างง่ายดายและดำเนินการเธรดเฉพาะด้วยการตั้งค่าที่ถูกต้อง นั่นคือเธรดที่อ่านข้อมูลจะถูกดำเนินการก่อน ทันทีที่เรามีข้อมูล จากนั้นเราจะส่งต่อไปยังเธรดที่รับผิดชอบในการตรวจสอบความถูกต้อง หลังจากนั้นเราส่งต่อไปยังเธรดเพื่อดำเนินการตามตรรกะทางธุรกิจและเธรดใหม่เขียนกลับ ในสถานการณ์เช่นนี้ 4 เธรดกำลังประมวลผลข้อมูลตามลำดับ และทุกอย่างจะทำงานได้เร็วกว่าเธรดเดียว แต่ละสตรีมดังกล่าวจะถูกแปลงเป็นสตรีมระบบปฏิบัติการดั้งเดิม แต่จะแปลงอย่างไรนั้นขึ้นอยู่กับการนำ JVM ไปใช้งาน
คลาสเธรดใช้เพื่อสร้างและทำงานกับเธรด มีกลไกควบคุมมาตรฐาน เช่นเดียวกับกลไก ที่เป็นนามธรรม เช่น คลาสและคอลเลกชันจากjava.util.concurrent
การซิงโครไนซ์เธรดใน Java
การสื่อสารมีให้โดยการแบ่งปันการเข้าถึงวัตถุ สิ่งนี้มีประสิทธิภาพมาก แต่ในขณะเดียวกันก็เกิดข้อผิดพลาดได้ง่ายมากเมื่อทำงาน ข้อผิดพลาดเกิดขึ้นได้สองกรณี: การรบกวนเธรด - เมื่อเธรดอื่นรบกวนเธรดของคุณ และข้อผิดพลาดความสอดคล้องของหน่วยความจำ - ความสอดคล้องของหน่วยความจำ เพื่อแก้ไขและป้องกันข้อผิดพลาดเหล่านี้ เรามีวิธีการซิงโครไนซ์ที่แตกต่างกัน
การซิงโครไนซ์เธรดใน Java จัดการโดยมอนิเตอร์ ซึ่งเป็นกลไกระดับสูงที่อนุญาตให้เธรดเพียงหนึ่งเธรดดำเนินการบล็อกของโค้ดที่ป้องกันโดยมอนิเตอร์เดียวกันในแต่ละครั้ง พฤติกรรมของจอภาพจะพิจารณาในแง่ของการล็อก หนึ่งจอภาพ - หนึ่งล็อค
การซิงโครไนซ์มีประเด็นสำคัญหลายประการที่คุณต้องให้ความสนใจ จุดแรกคือการยกเว้นร่วมกัน - มีเพียงหนึ่งเธรดเท่านั้นที่สามารถเป็นเจ้าของจอภาพได้ ดังนั้น การซิงโครไนซ์บนจอภาพหมายความว่าเมื่อเธรดหนึ่งเข้าสู่บล็อกซิงโครไนซ์ที่ป้องกันโดยจอภาพ เธรดอื่น ๆ ไม่สามารถเข้าสู่บล็อกที่ป้องกันโดยจอภาพนี้ จอภาพนี้ จนกระทั่ง เธรดแรกออกจากบล็อกที่ซิงโครไนซ์ นั่นคือหลายเธรดไม่สามารถเข้าถึงบล็อกซิงโครไนซ์เดียวกันได้ในเวลาเดียวกัน
แต่การซิงโครไนซ์ไม่ได้เป็นเพียงการกีดกันซึ่งกันและกันเท่านั้น การซิงโครไนซ์ช่วยให้มั่นใจได้ว่าข้อมูลที่เขียนไปยังหน่วยความจำก่อนหรือภายในบล็อกที่ซิงโครไนซ์จะปรากฏให้เห็นกับเธรดอื่นๆ ที่ซิงโครไนซ์บนจอภาพเดียวกัน หลังจากออกจากบล็อกแล้ว เราจะปล่อยจอภาพและเธรดอื่นสามารถจับได้และเริ่มดำเนินการบล็อกโค้ดนี้
เมื่อเธรดใหม่จับมอนิเตอร์ เราจะเข้าถึงและความสามารถในการเรียกใช้บล็อกโค้ดนั้น และเมื่อถึงเวลานั้น ตัวแปรจะถูกโหลดจากหน่วยความจำหลัก จากนั้นเราจะเห็นรายการทั้งหมดที่แสดงโดยจอภาพรุ่นก่อนหน้า
การอ่าน-เขียนบนฟิลด์เป็นการดำเนินการในระดับปรมาณู หากฟิลด์นั้นถูกประกาศให้เปลี่ยนแปลงหรือป้องกันโดยล็อคเฉพาะที่ได้มาก่อนการอ่าน-เขียนใดๆ แต่ถ้าคุณยังคงพบข้อผิดพลาด คุณจะได้รับข้อผิดพลาดเกี่ยวกับการจัดลำดับใหม่ (เปลี่ยนลำดับ จัดลำดับใหม่) มันปรากฏตัวในโปรแกรมมัลติเธรดที่ซิงโครไนซ์อย่างไม่ถูกต้อง โดยที่เธรดหนึ่งสามารถสังเกตผลกระทบที่เกิดจากเธรดอื่นได้ผลของการยกเว้นร่วมกันและการซิงโครไนซ์ของเธรด กล่าวคือ การดำเนินการที่ถูกต้องทำได้โดยการป้อนบล็อกหรือเมธอดที่ซิงโครไนซ์ซึ่งได้รับการล็อกโดยปริยาย หรือโดยการได้รับการล็อกอย่างชัดแจ้ง เราจะพูดถึงมันด้านล่าง วิธีการทำงานทั้งสองแบบส่งผลต่อความจำของคุณ และสิ่งสำคัญคือต้องไม่ลืมเกี่ยวกับการทำงานกับตัวแปรผันผวน
ฟิลด์ผันผวนใน Java
หากมีการทำเครื่องหมายตัวแปรที่เปลี่ยนแปลงได้ ตัวแปรนั้นจะสามารถใช้ได้ทั่วโลก ซึ่งหมายความว่าหากเธรดเข้าถึง ตัวแปรที่ เปลี่ยนแปลงได้เธรดจะได้รับค่าก่อนที่จะใช้ค่าจากแคช
การเขียนทำงานเหมือนกับการเผยแพร่จอภาพ และการอ่านทำงานเหมือนกับการจับภาพจอภาพ การเข้าถึงจะดำเนินการในความสัมพันธ์ของประเภท "ดำเนินการก่อน" หากคุณเข้าใจ สิ่งที่จะมองเห็นได้ในเธรด A เมื่อเข้าถึง ตัวแปรที่ เปลี่ยนแปลงได้คือตัวแปรสำหรับเธรด B นั่นคือรับประกันว่าคุณจะไม่สูญเสียการเปลี่ยนแปลงจากเธรดอื่น
ตัวแปร ที่ระเหยได้คือปรมาณูนั่นคือเมื่ออ่านตัวแปรดังกล่าวจะใช้เอฟเฟกต์เดียวกันกับเมื่อได้รับการล็อค - ข้อมูลในหน่วยความจำจะถูกประกาศว่าไม่ถูกต้องหรือไม่ถูกต้องและค่าของตัวแปรที่ระเหยได้จะถูกอ่านอีกครั้งจากหน่วยความจำ เมื่อเขียนจะใช้เอฟเฟกต์กับหน่วยความจำเช่นเดียวกับเมื่อปลดล็อค - ฟิลด์ ลบเลือนจะถูกเขียนลงในหน่วยความจำ
Java พร้อมกัน
หากคุณต้องการสร้างแอ็ พพลิเคชันแบบ multi-threaded ที่มีประสิทธิภาพสูง คุณต้องใช้คลาสจาก ไลบรารี JavaConcurrentซึ่งอยู่ใน แพ็คเกจ java.util.concurrent
ไลบรารีมีขนาดใหญ่มากและมีฟังก์ชันการทำงานที่แตกต่างกัน มาดูกันว่ามีอะไรอยู่ข้างในและแบ่งออกเป็นโมดูลต่างๆ:
![Java พร้อมกัน](https://cdn.codegym.cc/images/article/5490390d-0701-4845-807a-a7441f865074/1024.jpeg)
Concurrent Collectionsเป็นชุดของคอลเลกชันสำหรับการทำงานในสภาพแวดล้อมแบบมัลติเธรด แทนที่จะใช้ wrapper Collections.synchronizedList พื้นฐานที่มีการบล็อกการเข้าถึงคอลเล็กชันทั้งหมด การล็อกจะใช้กับกลุ่มข้อมูลหรือใช้อัลกอริทึมที่ไม่มีการรอเพื่ออ่านข้อมูลแบบขนาน
Queues - คิวที่ไม่บล็อกและบล็อกสำหรับการทำงานในสภาพแวดล้อมแบบมัลติเธรด คิวที่ไม่ปิดกั้นเน้นที่ความเร็วและการดำเนินการโดยไม่ปิดกั้นเธรด การบล็อกคิวเหมาะสำหรับการ ทำงานเมื่อคุณต้องการ "ชะลอ" เธรดของ ผู้ผลิตหรือผู้บริโภค ตัวอย่างเช่น ในสถานการณ์ที่ไม่เป็นไปตามเงื่อนไขบางประการ คิวว่างเปล่าหรือเต็ม หรือไม่มี Consumer 'a
Synchronizersเป็นโปรแกรมอรรถประโยชน์สำหรับการซิงโครไนซ์เธรด เป็นอาวุธที่ทรงพลังในการประมวลผลแบบ "ขนาน"
Executorsเป็นเฟรมเวิร์กสำหรับการสร้างเธรดพูลที่สะดวกและง่ายดายยิ่งขึ้น ง่ายต่อการตั้งค่ากำหนดการของงานอะซิงโครนัสพร้อมรับผลลัพธ์
ล็อคเป็นกลไกการซิงโครไนซ์เธรดที่ยืดหยุ่นมากมายเมื่อเทียบกับซิงโครไนซ์ พื้นฐาน ,รอ ,แจ้งเตือน ,แจ้งเตือนทั้งหมด
อะตอมเป็นคลาสที่สามารถรองรับการทำงานของอะตอมบนพื้นฐานและการอ้างอิง