1. บทนำ
บทสรุปของความเข้าใจของฉันเกี่ยวกับการสื่อสารระหว่างเธรดในรูปแบบมัลติเธรดจาวาส่วนใหญ่พูดถึงการสื่อสารระหว่างเธรดในรหัสที่รวมกับข้อความดังนั้นฉันจึงตัดข้อความตัวอย่างบางอย่างในหนังสือ
2. วิธีการสื่อสารระหว่างเธรด
①การซิงโครไนซ์
การซิงโครไนซ์ที่กล่าวถึงที่นี่หมายถึงหลายเธรดโดยใช้คำหลักที่ซิงโครไนซ์เพื่อรับรู้การสื่อสารระหว่างเธรด
ตัวอย่างอ้างอิง:
คลาสสาธารณะ myObject {โมฆะโมฆะสาธารณะที่ซิงโครไนซ์ซิงโครไนซ์ () {// ทำอะไรบางอย่าง .... } โมฆะสาธารณะที่ซิงโครไนซ์วิธีการ () {// ทำสิ่งอื่น}} ชั้นเรียนสาธารณะขยายเธรด {วัตถุ myObject ส่วนตัว; // ละเว้น constructor Object.methoda (); }} ThreadB คลาสสาธารณะขยายเธรด {วัตถุส่วนตัว myObject; // ละเว้นตัวสร้าง @Override โมฆะสาธารณะเรียกใช้ () {super.run (); Object.methodb (); }} การเรียกใช้คลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myObject object = new myObject (); // เธรด A และเธรด B ถือวัตถุเดียวกัน: Object Threada a = new Threada (Object); Threadb b = threadb ใหม่ (วัตถุ); A.Start (); B.Start (); -เนื่องจากเธรด A และเธรด B ถือวัตถุวัตถุของคลาส myobject เดียวกันแม้ว่าเธรดทั้งสองนี้จำเป็นต้องเรียกวิธีการที่แตกต่างกัน ตัวอย่างเช่นเธรด B จำเป็นต้องรอเธรด A เพื่อดำเนินการวิธี Methoda () ก่อนที่จะสามารถเรียกใช้วิธี MethodB () ด้วยวิธีนี้เธรด A และ Thread B ตระหนักถึงการสื่อสาร
วิธีนี้เป็นหลัก "การสื่อสารหน่วยความจำที่ใช้ร่วมกัน" หลายเธรดจำเป็นต้องเข้าถึงตัวแปรที่ใช้ร่วมกันเดียวกันและใครก็ตามที่ได้รับการล็อค (รับสิทธิ์การเข้าถึง) สามารถดำเนินการได้
②ในขณะที่วิธีการสำรวจ
รหัสมีดังนี้:
นำเข้า java.util.arraylist; นำเข้า java.util.list; คลาสสาธารณะ mylist {รายการส่วนตัว <String> list = new ArrayList <String> (); โมฆะสาธารณะเพิ่ม () {list.add ("องค์ประกอบ"); } ขนาด int สาธารณะ () {return list.size (); }} นำเข้า mylist.mylist; Threada คลาสสาธารณะขยายเธรด {รายการ MyList ส่วนตัว; Public Threada (รายการ mylist) {super (); this.list = list; } @Override โมฆะสาธารณะเรียกใช้ () {ลอง {สำหรับ (int i = 0; i <10; i ++) {list.add (); System.out.println ("เพิ่ม" + (i + 1) + "องค์ประกอบ"); Thread.sleep (1,000); }} catch (interruptedException e) {e.printStackTrace (); }}} นำเข้า mylist.mylist; Threadb คลาสสาธารณะขยายเธรด {รายการ mylist ส่วนตัว; Public Threadb (รายการ mylist) {super (); this.list = list; } @Override โมฆะสาธารณะเรียกใช้ () {ลอง {ในขณะที่ (จริง) {ถ้า (list.size () == 5) {system.out.println ("== 5, เธรด B พร้อมที่จะออก"); โยน InterruptedException ใหม่ (); }}} catch (interruptedException e) {e.printStackTrace (); }}} นำเข้า mylist.mylist; นำเข้า extthread.threada; นำเข้า extthread.threadb; การทดสอบระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {mylist service = new mylist (); threada a = threada ใหม่ (บริการ); A.setName ("A"); A.Start (); threadb b = threadb ใหม่ (บริการ); B.SetName ("B"); B.Start (); -ด้วยวิธีนี้เธรด A จะเปลี่ยนแปลงเงื่อนไขอย่างต่อเนื่องและเธรดเธรดจะตรวจพบอย่างต่อเนื่องว่าเงื่อนไขนี้ (list.size () == 5) เป็นจริงผ่านคำสั่งขณะนี้ซึ่งจะตระหนักถึงการสื่อสารระหว่างเธรด แต่วิธีนี้จะเสียทรัพยากร CPU เหตุผลที่ทำให้ทรัพยากรสูญเสียคือเมื่อ JVM Scheduler ส่ง CPU ไปยังเธรด B สำหรับการดำเนินการมันไม่ได้ทำงาน "มีประโยชน์" ใด ๆ แต่เป็นการทดสอบอย่างต่อเนื่องว่าเงื่อนไขบางอย่างเป็นจริง มันคล้ายกับในชีวิตจริงใครบางคนยังคงดูว่าโทรศัพท์กำลังเข้ามาบนหน้าจอโทรศัพท์มือถือของเขาแทนที่จะทำอย่างอื่นเมื่อโทรศัพท์กำลังมาเสียงเรียกเข้าจะแจ้งให้เขาทราบว่าโทรศัพท์กำลังมา
③ Wait/Notify Mechanism
รหัสมีดังนี้:
นำเข้า java.util.arraylist; นำเข้า java.util.list; คลาสสาธารณะ mylist {รายการคงที่ส่วนตัว <String> list = new ArrayList <String> (); โมฆะคงที่สาธารณะเพิ่ม () {list.add ("anystring"); } ขนาด int คงที่สาธารณะ () {return list.size (); }} คลาสสาธารณะเธรดขยายเธรด {ล็อควัตถุส่วนตัว; Threada สาธารณะ (ล็อควัตถุ) {super (); this.lock = ล็อค; } @Override โมฆะสาธารณะเรียกใช้ () {ลอง {ซิงโครไนซ์ (ล็อค) {ถ้า (mylist.size ()! = 5) {system.out.println ("รอเริ่มต้น" + System.currentTimeLis ()); lock.wait (); System.out.println ("Wait End" + System.currentTimeMillis ()); }}} catch (interruptedException e) {e.printStackTrace (); }}} ThreadB คลาสสาธารณะขยายเธรด {ล็อควัตถุส่วนตัว; Threadb สาธารณะ (ล็อควัตถุ) {super (); this.lock = ล็อค; } @Override โมฆะสาธารณะเรียกใช้ () {ลอง {ซิงโครไนซ์ (ล็อค) {สำหรับ (int i = 0; i <10; i ++) {mylist.add (); if (mylist.size () == 5) {lock.notify (); System.out.println ("แจ้งเตือน"); } system.out.println ("เพิ่ม" + (i + 1) + "องค์ประกอบ!"); Thread.sleep (1,000); }}} catch (interruptedException e) {e.printStackTrace (); }}} การเรียกใช้คลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ลอง {object lock = new Object (); threada a = threada ใหม่ (ล็อค); A.Start (); Thread.sleep (50); Threadb b = threadb ใหม่ (ล็อค); B.Start (); } catch (interruptedException e) {e.printStackTrace (); -เธรด A ต้องรอเงื่อนไขบางประการที่จะพึงพอใจก่อนที่จะทำการดำเนินการ เธรด B เพิ่มองค์ประกอบในรายการและเปลี่ยนขนาดของรายการ
A และ B สื่อสารได้อย่างไร? กล่าวอีกนัยหนึ่งเธรดรู้ว่า list.size () มีอยู่แล้ว 5?
ที่นี่เราใช้วิธีการรอ () และแจ้ง () วิธีการของคลาสวัตถุ
เมื่อเงื่อนไขไม่เป็นไปตาม (list.size ()! = 5) เธรดการโทรรอ () เพื่อละทิ้ง CPU และเข้าสู่สถานะการบล็อก --- อย่าใช้ CPU เช่น②ในขณะที่การสำรวจ
เมื่อพบเงื่อนไขการโทรเธรด B แจ้งเตือน () เพื่อแจ้งเธรด A. เธรดการแจ้งเตือนที่เรียกว่า A คือการปลุกเธรด A และปล่อยให้มันป้อนสถานะที่เรียกใช้ได้
ข้อดีอย่างหนึ่งของวิธีนี้คือการใช้ CPU ได้รับการปรับปรุง
แต่มีข้อเสียบางประการ: ตัวอย่างเช่นเธรด B ดำเนินการก่อนเพิ่ม 5 องค์ประกอบพร้อมกันและการโทรแจ้ง () เพื่อส่งการแจ้งเตือนและเธรด A ยังคงดำเนินการอยู่ เมื่อเธรดการดำเนินการและการโทรรอ () มันจะไม่ถูกปลุก เนื่องจากเธรด B ได้ออกการแจ้งเตือนแล้วและจะไม่ออกการแจ้งเตือนใด ๆ ในอนาคต นี่แสดงให้เห็นว่า การแจ้งเตือนนั้นเร็วเกินไปและจะขัดขวางตรรกะการดำเนินการของโปรแกรม
บทความข้างต้นเข้าใจวิธีการสื่อสารอย่างลึกซึ้งระหว่างกระทู้มัลติเธรด Java เป็นเนื้อหาทั้งหมดที่ฉันแบ่งปันกับคุณ ฉันหวังว่ามันจะให้ข้อมูลอ้างอิงและฉันหวังว่าคุณจะสนับสนุน wulin.com มากขึ้น