บทความนี้ส่วนใหญ่ศึกษารหัสที่เกี่ยวข้องตัวอย่างของเทคโนโลยีการสื่อสารการซิงโครไนซ์แบบดั้งเดิมของการเกิดขึ้นพร้อมกันของ Java ดังต่อไปนี้
มาดูคำถามก่อน:
มีสองเธรด เธรดเด็กจะดำเนินการ 10 ครั้งก่อนจากนั้นเธรดหลักจะดำเนินการ 5 ครั้งจากนั้นสลับไปที่เธรดลูกจะดำเนินการ 10 จากนั้นเธรดหลักจะดำเนินการ 5 ครั้ง ... การเดินทางไปรอบนี้คือ 50 ครั้ง
หลังจากอ่านคำถามนี้เป็นที่ชัดเจนว่าใช้การสื่อสารระหว่างเธรด ให้ฉันวิเคราะห์ความคิดก่อน: ก่อนอื่นต้องมีสองเธรดและจากนั้นจะต้องมี 50 ลูปในแต่ละเธรดเนื่องจากแต่ละเธรดต้องทำงาน 50 ครั้งการเดินทางไปกลับงานของเธรดหลักคือการดำเนินการ 5 ครั้งและภารกิจของเธรดเด็กคือการดำเนินการ 10 ครั้ง เทคโนโลยีการสื่อสารระหว่างเธรดส่วนใหญ่ใช้วิธี wait() และวิธี notify() วิธีการรอ () ทำให้เธรดปัจจุบันรอและปล่อยล็อคที่จัดขึ้น วิธี notify() ระบุว่าเธรดเดียวที่รออยู่บนจอภาพวัตถุนี้ถูกปลุกให้ตื่น มาทำปัญหาการสื่อสารระหว่างเธรดให้เสร็จทีละขั้นตอน
ขั้นแรกโดยไม่คำนึงถึงการสื่อสารระหว่างเธรดหลักและเธรดลูกให้เขียนงานที่จะดำเนินการโดยแต่ละเธรด:
คลาสสาธารณะแบบดั้งเดิม ThreadCommunication {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {// เปิดเธรดลูกใหม่ (ใหม่ runnable () {@Override โมฆะสาธารณะเรียกใช้ () {สำหรับ (int i = 1; i <= 50; i ++) {ซิงโครไนซ์ {system.out.println ("ลำดับเธรดย่อยของ" +j +", loop ของ" +i);}}}}}) เริ่มต้น (); // วิธีหลักคือเธรดหลักสำหรับ (int i = 1; i <= 50; i ++) {system.out.println ("ลำดับเธรดหลักของ" + j + ", ลูปของ" + i);}}}}}}}}}}}}}}}}}}}}}}}ดังที่ได้กล่าวไว้ข้างต้นสองเธรดแต่ละตัวมีลูปขนาดใหญ่ 50 ลูปและดำเนินการ 50 งานงานของเธรดลูกจะถูกดำเนินการ 10 ครั้งและงานหลักของเธรดจะถูกดำเนินการ 5 ครั้ง เพื่อให้แน่ใจว่าการซิงโครไนซ์ระหว่างสองเธรดใช้บล็อกรหัสซิงโครไนซ์ซิงโครไนซ์และใช้การล็อคเดียวกัน: วัตถุไบต์ของคลาส สิ่งนี้ทำให้มั่นใจได้ถึงความปลอดภัยของด้าย แต่การออกแบบนี้ไม่ค่อยดีนัก เช่นเดียวกับที่ฉันเขียนไว้ในการหยุดชะงักในส่วนก่อนหน้านี้เราสามารถใส่งานเธรดลงในชั้นเรียน รูปแบบของการออกแบบนี้มีโครงสร้างมากขึ้นและการวางงานเธรดที่แตกต่างกันลงในคลาสเดียวกันจะแก้ปัญหาการซิงโครไนซ์ได้อย่างง่ายดายเพราะง่ายต่อการใช้ล็อคเดียวกันในชั้นเรียน ดังนั้นแก้ไขโปรแกรมข้างต้น:
คลาสสาธารณะแบบดั้งเดิม ThreadCommunication {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ธุรกิจธุรกิจ = ธุรกิจใหม่ (); // ใหม่คลาสการประมวลผลงานเธรด // เปิดเธรดเด็กใหม่ (ใหม่ runnable () {@Override public void run () {สำหรับ (int i = 1; i <= 50; เธรดหลักสำหรับ (int i = 1; i <= 50; i ++) {bussiness.main (i);}}} // ข้อมูลทั่วไป (รวมถึงการเชื่อมต่อการซิงโครไนซ์) หรือวิธีการทั่วไปหลายวิธีที่จะใช้ควรจัดอยู่ในคลาสเดียวกัน การออกแบบนี้สะท้อนให้เห็นถึงความทนทานของโปรแกรมการจัดกลุ่มระดับสูง ธุรกิจชั้นเรียน {public synchronized void sub (int i) {สำหรับ (int j = 1; j <= 10; j ++) {system.out.println ("ลำดับหัวข้อย่อยของ" +j +", ลูปของ" +i);}} public synchronized void main (int i) j + ", loop of" + i);}} หลังจากการดัดแปลงนี้โครงสร้างโปรแกรมจะชัดเจนขึ้นและมีความแข็งแกร่งมากขึ้น เพียงเพิ่มคำหลักที่ซิงโครไนซ์ลงในสองวิธีการทำงานเธรดและใช้การล็อคนี้ แต่ยังไม่มีการสื่อสารระหว่างสองเธรด ผลของการดำเนินการคือเธรดหลักจะวนภารกิจ 50 ครั้งและเธรดลูกจะวนภารกิจ 50 ครั้ง เหตุผลนั้นง่ายมากเพราะมีการซิงโครไนซ์ซิงโครไนซ์
ต่อไปนี้ยังคงปรับปรุงโปรแกรมเพื่อให้การสื่อสารระหว่างสองเธรดตามที่อธิบายไว้ในคำถาม:
คลาสสาธารณะแบบดั้งเดิม ThreadCommunication {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ธุรกิจธุรกิจ = ธุรกิจใหม่ (); // ใหม่คลาสการประมวลผลงานเธรด // เปิดเธรดเด็กใหม่ (ใหม่ runnable () {@Override public void run () {สำหรับ (int i = 1; i <= 50; เธรดหลักสำหรับ (int i = 1; i <= 50; i ++) {bussiness.main (i);}}} // เพื่อใช้ข้อมูลทั่วไป (รวมถึงการเชื่อมต่อการซิงโครไนซ์) หรือวิธีการทั่วไปหลายวิธีควรแบ่งออกเป็นคลาสเดียวกัน การออกแบบนี้สะท้อนให้เห็นถึงความแข็งแกร่งของละคร Gao Lei และโปรแกรม ธุรกิจชั้นเรียน {บูลีนส่วนตัว bshouldsub = true; โมฆะย่อยที่ซิงโครไนซ์สาธารณะ (int i) {ในขณะที่ (! bshouldsub) {// ถ้ามันไม่ใช่ตาของคุณที่จะดำเนินการลอง {this.wait (); // วัตถุที่เรียกวิธีการรอ () ที่นี่ซิงโครไนซ์อยู่ในวิธีการดังนั้นใช้} catch (interruptedException e) {// toDo catch blocke.printstacktrace () {// toDo สำหรับ (int j = 1; j <= 10; j ++) this.notify (); // ปลุกเธรดหลักที่รออยู่} โมฆะที่ซิงโครไนซ์สาธารณะ (int i) {ในขณะที่ (bshouldsub) {// ถ้าไม่ใช่ตาของคุณที่จะดำเนินการลอง {this.wait ();} catch (interruptedexception e) {// todo ++) {system.out.println ("ลำดับเธรดหลักของ" + j + ", loop ของ" + i);} bshouldsub = true; // เปลี่ยนแท็ก this.notify (); // ปลุกเธรดเด็กที่รอ}}}}}ก่อนอื่นอย่าพูดคุยเกี่ยวกับการใช้งานโปรแกรมเฉพาะจากมุมมองเชิงโครงสร้างเราได้ตระหนักถึงประโยชน์ของการออกแบบนี้แล้ว: ไม่จำเป็นต้องแก้ไขอะไรในฟังก์ชั่นหลักและตรรกะเกี่ยวกับการซิงโครไนซ์ระหว่างเธรดและการสื่อสารระหว่างเธรดล้วนอยู่ในชั้นธุรกิจ เธรดที่แตกต่างกันในฟังก์ชั่นหลักจำเป็นต้องเรียกงานที่เกี่ยวข้องที่วางไว้ในชั้นเรียน มันสะท้อนให้เห็นถึงประโยชน์ของ flocking สูง
มาดูรหัสเฉพาะอีกครั้ง ขั้นแรกให้กำหนดตัวแปรบูลีนเพื่อระบุว่าควรดำเนินการเธรดใด เมื่อไม่ใช่ด้ายเด็กมันจะนอนหลับ จากนั้นมันจะดำเนินการตามธรรมชาติของเธรดหลัก หลังจากการดำเนินการมันจะแก้ไข bshouldsub และปลุกเธรดลูก ในเวลานี้กระทู้เด็กจะตัดสินว่าในขณะที่ไม่พอใจและจะไม่นอน มันจะดำเนินการงานเธรดเด็ก ในทำนองเดียวกันหลังจากเธรดหลักเพิ่งแก้ไข bshouldsub เมื่อลูปที่สองถูกใช้เพื่อดำเนินการงานเธรดหลักมันจะนอนหลับและรอให้เธรดลูกตื่นขึ้นมา สิ่งนี้ทำให้ตรรกะชัดเจนมาก เธรดหลักและเธรดเด็กผลัดกันทำงานตามลำดับและจังหวะนี้มีทั้งหมด 50 เท่า
มีคำอธิบายเล็ก ๆ น้อย ๆ : เป็นไปได้จริงที่จะใช้ถ้าจะตัดสิน แต่ทำไมใช้ในขณะที่? เพราะบางครั้งเธรดจะตื่นขึ้นมาอย่างน่ากลัว (มันก็เหมือนกับการเดินนอนหลับซึ่งเห็นได้ชัดว่านอนหลับ แต่ยืนขึ้น) ถ้ามันใช้ถ้าหลังจากนั้นก็ตื่นขึ้นมาแล้วมันจะไม่กลับไปตัดสินถ้าและจากนั้นมันจะดำเนินงานตามธรรมชาติ โอเคเธรดอื่นกำลังดำเนินการและมันจะส่งผลกระทบต่อเธรดอื่นในแฟลช แต่ถ้าเป็นเวลาสักพักมันจะแตกต่างกัน แม้ว่าเธรดจะตื่นขึ้นมาอย่างไม่ดี แต่ก็ยังคงตัดสินในขณะที่ อย่างไรก็ตามเธรดอื่นกำลังดำเนินการในเวลานี้ Bshouldsub ยังไม่ได้รับการแก้ไขดังนั้นจึงยังคงเข้ามาในขณะที่และนอนหลับอีกครั้ง ~ ดังนั้นจึงปลอดภัยมากและจะไม่ส่งผลกระทบต่อหัวข้ออื่น! สิ่งนี้ทำในเอกสาร JDK อย่างเป็นทางการ
มาสรุปการสื่อสารระหว่างเธรด
ข้างต้นเป็นคำอธิบายโดยละเอียดทั้งหมดของรหัสการสื่อสารการซิงโครไนซ์แบบดั้งเดิมรหัสเทคโนโลยีของ Java พร้อมกันและฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!