1 ปัญหาการเกิดขึ้นพร้อมกันคืออะไร
หลายกระบวนการหรือเธรดที่เข้าถึงทรัพยากรเดียวกันพร้อมกัน (หรือในช่วงเวลาเดียวกัน) จะทำให้เกิดปัญหาพร้อมกัน
ตัวอย่างทั่วไปคือผู้ให้บริการธนาคารสองรายดำเนินการบัญชีเดียวกันในเวลาเดียวกัน ตัวอย่างเช่นผู้ประกอบการ A และ B อ่านบัญชีที่มียอดคงเหลือ 1,000 หยวนในเวลาเดียวกันผู้ประกอบการ A เพิ่ม 100 หยวนลงในบัญชีผู้ประกอบการ B ยังลดลง 50 หยวนสำหรับบัญชีการส่งก่อนและ B ส่งในภายหลัง ยอดเงินจริงสุดท้ายคือ 1,000-50 = 950 หยวน แต่ควรจะเป็น 1,000+100-50 = 1050 นี่เป็นปัญหาร่วมกันทั่วไป วิธีแก้ปัญหา? สามารถใช้ล็อค
2 การใช้งานของซิงโครไนซ์ในชวา
การใช้งาน 1
การทดสอบระดับสาธารณะ {public synchronized void print () {….;}}หากเธรดดำเนินการวิธีการพิมพ์ () วัตถุจะถูกล็อค เธรดอื่น ๆ จะไม่สามารถเรียกใช้บล็อกที่ซิงโครไนซ์ทั้งหมดของวัตถุได้
การใช้งาน 2
การทดสอบระดับสาธารณะ {public void print () {ซิงโครไนซ์ (นี่) {// ล็อควัตถุนี้…;}}} การใช้งานเดียวกัน 1 แต่มันสามารถสะท้อนถึงสาระสำคัญของการใช้งานที่ซิงโครไนซ์ได้ดีขึ้น
การใช้งาน 3
การทดสอบคลาสสาธารณะ {สตริงส่วนตัว a = "ทดสอบ"; การพิมพ์โมฆะสาธารณะ () {ซิงโครไนซ์ (a) {// ล็อควัตถุ ... ;}} โมฆะที่ซิงโครไนซ์สาธารณะ t () {…; // บล็อกรหัสที่ซิงโครไนซ์นี้จะไม่ถูกล็อคเนื่องจากการพิมพ์ ()}}}}}}}}}}}}}การดำเนินการพิมพ์ () จะล็อควัตถุ โปรดทราบว่ามันไม่ได้ล็อควัตถุของการทดสอบซึ่งหมายความว่าวิธีการซิงโครไนซ์อื่น ๆ ของวัตถุทดสอบจะไม่ถูกล็อคเนื่องจากการพิมพ์ () หลังจากดำเนินการบล็อกรหัสการซิงโครไนซ์แล้วล็อคไปยัง A จะถูกปล่อยออกมา
เพื่อล็อคบล็อกรหัสของวัตถุโดยไม่ส่งผลกระทบต่อการเขียนประสิทธิภาพสูงของบล็อกซิงโครไนซ์อื่น ๆ ของวัตถุ:
การทดสอบระดับสาธารณะ {ไบต์ส่วนตัว [] ล็อค = ไบต์ใหม่ [0]; การพิมพ์โมฆะสาธารณะ () {ซิงโครไนซ์ (ล็อค) {…;}} โมฆะที่ซิงโครไนซ์สาธารณะ t () {…;}}ล็อควิธีการคงที่
การทดสอบระดับสาธารณะ {โมฆะคงที่แบบสแตติกแบบซิงโครไนซ์สาธารณะ Execute () {…;}}เอฟเฟกต์เดียวกัน
การทดสอบคลาสสาธารณะ {โมฆะคงที่สาธารณะ Execute () {ซิงโครไนซ์ (testThread.class) {…;}}}}3 ล็อคในชวาและคิวขึ้นไปเข้าห้องน้ำ
ล็อคเป็นวิธีการป้องกันกระบวนการหรือเธรดอื่น ๆ จากการเข้าถึงทรัพยากรนั่นคือทรัพยากรที่ล็อคไม่สามารถเข้าถึงได้โดยคำขออื่น ๆ ใน Java คำหลัก sychronized ใช้เพื่อล็อควัตถุ ตัวอย่างเช่น:
mystack คลาสสาธารณะ {int idx = 0; char [] data = char ใหม่ [6]; publ push ที่ซิงโครไนซ์สาธารณะ (char c) {data [idx] = c; idx ++;} ถ่านที่ซิงโครไนซ์สาธารณะ () {idx-; return data [idx];} การพูดอย่างเคร่งครัดบล็อกของวัตถุที่ซิงโครไนซ์ทั้งหมดจะถูกล็อค หากมีเธรดอื่นที่พยายามเข้าถึง M แสดงว่า t ไม่สามารถเรียกใช้วิธีการกดและป๊อปของวัตถุ M */m.pop (); // วัตถุ m ถูกล็อค -การปลดล็อคล็อคของ Java นั้นเหมือนกับหลาย ๆ คนที่เข้าคิวเพื่อเข้าห้องน้ำสาธารณะ คนแรกล็อคประตูจากด้านในหลังจากเข้ามาดังนั้นคนอื่น ๆ จึงต้องรอเข้าแถว ประตูจะเปิด (ปลดล็อค) เฉพาะเมื่อคนแรกออกมาหลังจากสิ้นสุด มันเป็นตาคนที่สองที่จะเข้าไปข้างในและเขาจะล็อคประตูจากข้างในอีกครั้งและคนอื่น ๆ จะยังคงรออยู่ในแถวต่อไป
เป็นเรื่องง่ายที่จะเข้าใจการใช้ทฤษฎีห้องน้ำ: เมื่อคนเข้าห้องน้ำห้องน้ำจะถูกล็อค แต่มันจะไม่ทำให้ห้องน้ำอื่นถูกล็อคเพราะคนคนหนึ่งไม่สามารถนั่งยองในห้องสุขาสองห้องในเวลาเดียวกัน สำหรับ Java มันหมายถึง: ล็อคใน Java ถูกกำหนดเป้าหมายที่วัตถุเดียวกันไม่ใช่ที่ชั้นเรียน ดูตัวอย่างต่อไปนี้:
mystatckm1 = newmystack (); mystatckm2 = newMystatck (); m1.pop (); m2.pop ();
ล็อคของวัตถุ M1 จะไม่ส่งผลกระทบต่อล็อคของ M2 เพราะมันไม่ได้อยู่ในตำแหน่งห้องน้ำเดียวกัน กล่าวคือถ้ามี 3 เธรด T1, T2 และ T3 ที่ทำงาน M1 ดังนั้นเธรดทั้ง 3 นี้สามารถคิวและรอ M1 เท่านั้น สมมติว่าอีก 2 เธรด T8, T9 ทำงาน M2 จากนั้น T8, T9 จะรอ M2 เท่านั้น T2 และ T8 ไม่มีส่วนเกี่ยวข้องกับมัน แม้ว่าการล็อคบน M2 จะถูกปล่อยออกมา T1, T2 และ T3 อาจยังคงต้องเข้าคิวใน M1 ไม่มีเหตุผลมันไม่ใช่ที่นั่งส้วมเดียวกัน
Java ไม่สามารถเพิ่มสองล็อคลงในบล็อกรหัสในเวลาเดียวกัน สิ่งนี้แตกต่างจากกลไกการล็อคฐานข้อมูล ฐานข้อมูลสามารถเพิ่มล็อคที่แตกต่างกันหลายรายการในบันทึกในเวลาเดียวกัน
4 เมื่อฉันควรปล่อยล็อค?
โดยทั่วไปการล็อคจะถูกปล่อยออกมาหลังจากที่บล็อกรหัสการซิงโครไนซ์ (บล็อกรหัสล็อค) ถูกดำเนินการหรือล็อคสามารถปล่อยออกมาได้ครึ่งทางผ่านวิธีการรอ () วิธีการรอ () เป็นเหมือนการนั่งยองในห้องน้ำครึ่งทางและทันใดนั้นฉันก็พบว่าท่อระบายน้ำถูกบล็อก ฉันต้องออกมาและยืนหยัดเพื่อให้ผู้ซ่อมแซมท่อระบายน้ำ (เธรดที่พร้อมที่จะดำเนินการแจ้งเตือน) สามารถเข้าไปในและล้างห้องน้ำได้ หลังจากการปลดล็อคอาจารย์ตะโกนว่า: "มันได้รับการซ่อมแซมแล้ว" สหายที่ออกมาตอนนี้เข้าแถวอีกครั้งหลังจากได้ยินมัน ให้ความสนใจคุณต้องรอให้เจ้านายออกมา หากอาจารย์ไม่ได้ออกมาไม่มีใครสามารถเข้าไปได้นั่นคือหลังจากแจ้งเตือนเธรดอื่น ๆ สามารถเข้าสู่พื้นที่ที่ถูกบล็อกและย้ายไปรอบ ๆ ทันที แต่เธรดอื่น ๆ สามารถป้อนได้หลังจากพื้นที่ที่ถูกบล็อกซึ่งรหัสแจ้งเตือนถูกดำเนินการและปล่อยเพื่อปล่อยล็อค
นี่คือตัวอย่างการรอคอยและแจ้งรหัส:
ถ่านที่ซิงโครไนซ์สาธารณะป๊อป () {char c; ในขณะที่ (buffer.size () == 0) {ลอง {this.wait (); // ออกจากห้องน้ำ} catch (interruptedException e) {// ละเว้นมัน…}} c = (ตัวละคร) บัฟเฟอร์ charvalue (); return c;} โมฆะที่ซิงโครไนซ์สาธารณะแบบซิงโครไนซ์ (Char C) {this.notify (); // แจ้งให้ทราบว่าการรอ () เธรดเหล่านั้นจะเข้าคิวอีกครั้ง หมายเหตุ: เพียงแจ้งให้พวกเขาทราบอีกครั้ง ตัวละคร charobj = ตัวละครใหม่ (c); buffer.addelement (charobj);} // ดำเนินการและปล่อยล็อค เธรดที่เข้าคิวเหล่านั้นสามารถเข้ามาได้ลึกลงไป
เนื่องจากการดำเนินการรอ () สหายที่ออกมาครึ่งทางจะไม่เข้าคิวจนกว่าพวกเขาจะได้รับสัญญาณแจ้งเตือน เขาจะดูผู้คนที่เข้าคิวข้างเขา (อาจารย์ซ่อมท่อน้ำก็อยู่ในหมู่พวกเขาด้วย) โปรดทราบว่าอาจารย์ซ่อมท่อน้ำไม่สามารถไปที่บรรทัดและเขาจะต้องเข้าคิวเหมือนคนที่เข้าห้องน้ำ ไม่ใช่ว่าหลังจากที่มีคนออกไปครึ่งทางแล้วอาจารย์ซ่อมท่อน้ำสามารถปรากฏตัวขึ้นและเข้าไปในการซ่อมแซมทันที เขาต้องการที่จะแข่งขันอย่างยุติธรรมกับคนที่เคยเข้าคิวเพราะเขายังเป็นด้ายธรรมดา หากอาจารย์ซ่อมท่อน้ำเรียงรายอยู่ด้านหลังบุคคลที่อยู่ข้างหน้าจะพบว่ามันถูกบล็อกและรอจากนั้นออกมาและยืนรอรอออกมายืนหยัดและไปที่อาจารย์เพื่อเข้าไปข้างในและดำเนินการแจ้งเตือน ด้วยวิธีนี้หลังจากนั้นไม่นานจะมีคนจำนวนมากที่ยืนอยู่ถัดจากคิวรอการแจ้งเตือน
ในที่สุดอาจารย์ก็เข้าไปข้างในและแจ้ง ถัดไปคืออะไร?
1. คนรอ (เธรด) ได้รับแจ้ง
2. ทำไมเขาถึงได้รับแจ้งแทนที่จะเป็นคนรอคนอื่น? ขึ้นอยู่กับ JVM เราไม่สามารถจองล่วงหน้าได้
กำหนดว่าจะได้รับแจ้งใด กล่าวอีกนัยหนึ่งผู้ที่มีลำดับความสำคัญสูงอาจไม่ตื่นก่อนรอ
เวลาใดก็ตามที่ไม่จำเป็นต้องถูกปลุกให้ตื่นก่อนทุกอย่างไม่สามารถคาดเดาได้! (แน่นอนถ้าคุณรู้จัก JVM
หากดำเนินการคุณสามารถทำนายได้)
3. เขา (เธรดแจ้งเตือน) ต้องเข้าคิวอีกครั้ง
4. เขาจะอยู่ในสถานที่แรกในบรรทัดหรือไม่? คำตอบคือ: ไม่แน่ใจ เขาจะเป็นคนสุดท้ายหรือไม่? ไม่จำเป็น
แต่ถ้าลำดับความสำคัญของเธรดถูกตั้งค่าให้ค่อนข้างสูงความน่าจะเป็นของการจัดอันดับก่อนจะค่อนข้างสูง
5. เมื่อถึงตาของเขาที่จะเข้าสู่ที่นั่งห้องน้ำอีกครั้งเขาจะดำเนินการต่อจากการรอคอยครั้งสุดท้าย () สถานที่และจะไม่ execute อีกครั้ง
เพื่อให้มันน่าขยะแขยงเขาจะยังคงเดินเล่นต่อไปไม่ได้เดินเล่นอีกครั้ง
6. ถ้าอาจารย์แจ้งเตือน () แล้วทุกคนที่ยอมแพ้ครึ่งทางจะเข้าแถวอีกครั้ง คำสั่งไม่เป็นที่รู้จัก
Javadoc กล่าวว่า TheawakenedthreadswillnotNotBeableToproceedTilTheCurrentthreadRelInquishThelockonthisObject (เธรดที่ถูกปลุกไม่สามารถดำเนินการได้ก่อนที่เธรดปัจจุบันจะปล่อยล็อค)
นี่คือสิ่งที่ชัดเจนในการอธิบายโดยใช้ทฤษฎีที่นั่งห้องน้ำ
5 ล็อคการใช้งาน
ใช้คำหลักที่ซิงโครไนซ์เพื่อล็อคทรัพยากร คำหลักล็อคก็โอเค เป็นของใหม่ใน JDK1.5 การใช้งานมีดังนี้:
คลาส BoundedBuffer {ล็อคสุดท้ายล็อค = ใหม่ reentrantlock (); เงื่อนไขสุดท้าย notfull = lock.newcondition (); เงื่อนไขสุดท้าย notempty = lock.newcondition (); วัตถุสุดท้าย [] รายการ = วัตถุใหม่ [100]; int putptr, takeptr, count; notfull.await (); รายการ [putptr] = x; ถ้า (++ putptr == items.length) putptr = 0; ++ count; notempty.signal ();} ในที่สุด {lock.unlock ();}} วัตถุสาธารณะใช้ () รายการ [takeptr]; ถ้า (++ takeptr == items.length) takeptr = 0;-count; notfull.signal (); return x;} ในที่สุด {lock.unlock ();}}}(หมายเหตุ: นี่เป็นตัวอย่างใน javadoc ตัวอย่างการใช้งานของคิวการบล็อกสิ่งที่เรียกว่าคิวการบล็อกหมายความว่าหากคิวเต็มหรือว่างเปล่ามันจะทำให้เกิดการบล็อกและรอด้าย arrayblockingqueue ในชวา
รหัสระหว่าง lock.lock () และ lock.unlock () ของวัตถุจะถูกล็อค อะไรคือสิ่งที่ดีกว่าเกี่ยวกับวิธีนี้เมื่อเทียบกับการซิงโครไนซ์? ในระยะสั้นมันจำแนกประเภทรอ เพื่ออธิบายโดยใช้ทฤษฎีที่นั่งห้องน้ำผู้ที่นั่งยอง ๆ ครึ่งทางและออกมาจากที่นั่งส้วมและรออาจมีเหตุผลที่แตกต่างกัน บางคนเป็นเพราะห้องน้ำถูกบล็อกและบางส่วนเป็นเพราะห้องน้ำอยู่นอกน้ำ เมื่อแจ้งเตือนคุณสามารถตะโกน: หากคุณรอให้ห้องน้ำถูกบล็อกคุณจะกลับเข้าแถว (ตัวอย่างเช่นปัญหาของห้องน้ำที่ถูกบล็อกได้รับการแก้ไข) หรือตะโกนถ้าคุณรอให้ห้องน้ำถูกบล็อก สิ่งนี้ช่วยให้สามารถควบคุมรายละเอียดได้มากขึ้น แตกต่างจากการรอคอยและการแจ้งเตือนในการซิงโครไนซ์ไม่ว่าจะเป็นห้องน้ำถูกบล็อกหรือห้องน้ำไม่ได้เป็นน้ำคุณสามารถตะโกนได้เท่านั้น: ฉันรอที่นี่เพื่อเข้าคิว! หากผู้คนเข้าแถวเข้ามาและมองพวกเขาพบว่าปัญหาของห้องน้ำได้รับการแก้ไขและปัญหาที่พวกเขากระตือรือร้นที่จะแก้ปัญหา (ห้องน้ำไม่มีน้ำ) ยังไม่ได้รับการแก้ไขดังนั้นพวกเขาจึงต้องกลับไปรอ (รอ)
ความสัมพันธ์ที่สอดคล้องกันระหว่างวิธีการล็อคและซิงโครไนซ์:
lockawaitsignalsignalall
synchronizedwaitnotifynotifyall
หมายเหตุ: อย่าโทรรอแจ้งแจ้งแจ้งเตือนในบล็อกที่ล็อคโดยล็อค
6. ใช้ท่อเพื่อสื่อสารระหว่างเธรด
หลักการง่ายๆ สองเธรดหนึ่งทำงาน PipedInputStream และอื่น ๆ ทำงาน PipedOutputStream ข้อมูลที่เขียนโดย PipedOutputStream ถูกแคชในบัฟเฟอร์ก่อน หากบัฟเฟอร์เต็มเธรดนี้จะรอ PipedInputStream อ่านข้อมูลในบัฟเฟอร์ หากบัฟเฟอร์ไม่มีข้อมูลเธรดนี้จะรอ
ฟังก์ชั่นเดียวกันสามารถทำได้โดยการปิดกั้นคิวใน JDK1.5
แพ็คเกจ io; นำเข้า java.io.*; คลาสสาธารณะ pipedstreamtest {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {pipedoutputstream ops = ใหม่ pipedoutputstream (); pipedInputStream pis = new PipedInputStream () ผู้บริโภค (pis) .run ();} catch (Exception e) {E.printStackTrace ();}}} // ผู้ผลิตคลาสผู้ผลิตใช้งาน Runnable {pipedoutputStream private public ผู้ผลิต (PipedOutputStream ops) {this.Ops = ops; run () {ลอง {ops.write ("นรก, คาถา" .getBytes ()); ops.close ();} catch (ข้อยกเว้น e) {e.printstacktrace ();}}} // ผู้บริโภคในชั้นเรียน run () {ลอง {byte [] bu = byte ใหม่ [100]; int len = pis.read (bu); system.out.println (สตริงใหม่ (bu, 0, len)); pis.close ();} catch (ยกเว้น e) {e.printstacktrace ();ตัวอย่างที่ 2: การเปลี่ยนแปลงเล็กน้อยสำหรับโปรแกรมด้านบนกลายเป็นสองเธรด
แพ็คเกจ IO; นำเข้า java.io.*; คลาสสาธารณะ pipedstreamtest {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {pipedoutputStream ops = ใหม่ pipedoutputstream (); pipedInputStream pis = new PipedInputStream () เธรด (p) .start (); ผู้บริโภค c = ผู้บริโภคใหม่ (pis); เธรดใหม่ (c) .start ();} catch (ข้อยกเว้น e) {e.printstacktrace ();}}}} // ผู้ผลิตคลาสผู้ผลิต run () {ลอง {สำหรับ (;;) {ops.write ("นรก, คาถา" .getBytes ()); ops.close ();}}} // ผู้บริโภคในชั้นเรียนผู้บริโภคใช้งาน {pipedinputstream pis; (;;) {byte [] bu = byte ใหม่ [100]; int len = pis.read (bu); system.out.println (สตริงใหม่ (bu, 0, len));} pis.close ();} catch (ยกเว้น e) {e.printstacktrace ();}}}}ตัวอย่างที่ 3 ตัวอย่างนี้เหมาะสมกับแอปพลิเคชันมากกว่า
นำเข้า java.io.*; คลาสสาธารณะ pipedio {// หลังจากโปรแกรมทำงานแล้วให้คัดลอกเนื้อหาของไฟล์ sendfile ไปยังไฟล์ teadfile โมฆะสาธารณะคงที่หลัก (สตริง args []) {ลอง {// สร้าง read และเขียน posestream) posestream) Pos.Connect (pis); // สร้างสองเธรดและเริ่มต้น ผู้ส่งใหม่ (pos, "c:/text2.txt"). start (); ผู้รับใหม่ (pis, "c:/text3.txt"). start ();} catch (ioexception e) {system.out.println ("ข้อผิดพลาดท่อ" + e);}}}} // ผู้ส่ง (PipedOutputStream POS, String filename) {this.pos = pos; ไฟล์ = ไฟล์ใหม่ (ชื่อไฟล์);} // เธรดรันวิธีการเรียกใช้โมฆะสาธารณะเรียกใช้ () {ลอง {// อ่านเนื้อหาไฟล์ไฟล์ fileInputStream fs = ใหม่ fileInputStream (ไฟล์); int data; pos.write (data);} pos.close ();} catch (ioexception e) {system.out.println ("ข้อผิดพลาดของผู้ส่ง" +e);}}}} // ตัวรับคลาสเธรดขยาย {pipedInputStream pis; ไฟล์ไฟล์ // ไฟล์ (ชื่อไฟล์);} // เธรดรันโมฆะสาธารณะ run () {ลอง {// เขียนไฟล์สตรีมไฟล์วัตถุวัตถุ FileOutputStream fs = ใหม่ fileOutputStream (ไฟล์); ข้อมูล int; // อ่านในขณะที่ (data = pis.read ())! =-1) {// เขียนไปยังไฟล์ท้องถิ่น fs.write (data); e) {system.out.println ("ข้อผิดพลาดตัวรับสัญญาณ" +e);}}}7 บล็อกคิว
คิวการปิดกั้นสามารถแทนที่วิธีการไหลของท่อเพื่อใช้โหมดท่อทางเข้า/ระบายน้ำ (ผู้ผลิต/ผู้บริโภค) JDK1.5 มีคิวการปิดกั้นสำเร็จรูปหลายรายการ ตอนนี้ลองดูที่รหัสของ ArrayblockingQueue ดังต่อไปนี้:
นี่คือคิวการปิดกั้น
BlockingQueue BlockingQ = New ArrayBlockingQueue 10;
เธรดใช้จากคิว
สำหรับ (;;) {Object O = blockingq.take (); // คิวว่างเปล่าจากนั้นรอ (บล็อก)}เธรดอื่นจะถูกเก็บไว้ในคิว
สำหรับ (;;) {blockkingq.put (วัตถุใหม่ ()); // ถ้าคิวเต็มรอ (บล็อก)}จะเห็นได้ว่าการบล็อกคิวนั้นใช้งานง่ายกว่าท่อ
ผู้บริหาร 8 คน, ผู้ดำเนินการ, ExecutorService, ThreadPoolexecutor
คุณสามารถใช้งานการจัดการเธรด นอกจากนี้คุณยังสามารถใช้ชุดคลาสที่จัดทำโดย JDK1.5 เพื่อจัดการงานที่สะดวกยิ่งขึ้น จากหมวดหมู่เหล่านี้เราสามารถสัมผัสกับวิธีคิดที่มุ่งเน้นงาน ชั้นเรียนเหล่านี้คือ:
อินเทอร์เฟซผู้ดำเนินการ วิธีใช้:
Executor Executor = Anexecutor; // สร้างอินสแตนซ์ของผู้ดำเนินการ executor.execute (ใหม่ RunnableTask1 ());
ความตั้งใจ: ผู้ใช้มุ่งเน้นเฉพาะการดำเนินงานและไม่ต้องกังวลเกี่ยวกับการสร้างงานและรายละเอียดการดำเนินการและปัญหาอื่น ๆ ที่ผู้ดำเนินการบุคคลที่สามมีความกังวล กล่าวคือ decouple การเรียกใช้การเรียกใช้งานและการใช้งานงาน
ในความเป็นจริงมีการใช้งานที่ยอดเยี่ยมของอินเทอร์เฟซนี้ใน JDK1.5 เพียงพอ.
ผู้ดำเนินการเป็นคลาสโรงงานหรือคลาสเครื่องมือเช่นคอลเลกชันที่ใช้ในการสร้างอินสแตนซ์ของอินเทอร์เฟซต่างๆ
อินเทอร์เฟซ ExecutorService นั้นสืบทอดมาจาก Executor.Executor เพียงแค่โยนงานลงใน Executor () สำหรับการดำเนินการและละเว้นส่วนที่เหลือ ExecutorService แตกต่างกันมันจะทำงานควบคุมได้มากขึ้น ตัวอย่างเช่น:
Class Networkservice {Private Final Serversocket Serversocket; Private ExecutorService Pool; เครือข่ายสาธารณะ (พอร์ต int, int poolsize) โยน ioexception {serversocket = ใหม่เซิร์ฟเวอร์ (พอร์ต); pool = executors.newFixedThreadPool (poolsize) Handler (serversocket.accept ()));}} catch (ioexception ex) {pool.shutdown (); // ไม่มีงานใหม่ถูกดำเนินการ}}} ตัวจัดการคลาสใช้งาน {ซ็อกเก็ตซ็อกเก็ตสุดท้ายที่ใช้งานได้หลังจาก ExecutorService (นั่นคือวัตถุพูลในรหัส) ดำเนินการปิดระบบมันไม่สามารถดำเนินงานใหม่ได้อีกต่อไป แต่งานเก่าจะดำเนินการต่อไปและผู้ที่รอการดำเนินการจะไม่รออีกต่อไป
ผู้ส่งงานและการสื่อสารนักแสดง
โมฆะคงที่สาธารณะหลัก (String args []) โยนข้อยกเว้น {ExecutoRservice Executor = Executors.newsingLethreathedExecutor (); งานเรียกได้ = new callable () {การเรียกสตริงสาธารณะ () โยนข้อยกเว้น {กลับ "ทดสอบ";}}; System.out.println (ผลลัพธ์); executor.shutdown ();}อินสแตนซ์ของผู้ดำเนินการที่ได้รับจาก Executors.newsingLetHreadexecutor () มีคุณสมบัติดังต่อไปนี้:
การดำเนินการตามลำดับ ตัวอย่างเช่น:
Executor.submit (task1); executor.submit (task2);
คุณต้องรอให้ Task1 ถูกดำเนินการก่อนที่ TASSP2 จะสามารถดำเนินการได้
task1 และ task2 จะถูกวางไว้ในคิวและประมวลผลโดยเธรดคนงาน นั่นคือ: มี 2 เธรดทั้งหมด (เธรดหลัก, เธรดคนงานที่ประมวลผลงาน)
สำหรับชั้นเรียนอื่น ๆ โปรดดู javadoc
9 การควบคุมกระบวนการพร้อมกัน
ตัวอย่างในส่วนนี้มาจากการสอนพร้อมกันของ Java ของ Wen Shao และอาจมีการเปลี่ยนแปลง แสดงความยินดีกับ Mr. Wen
เคาน์เตอร์ PIN ประตูนับถอยหลัง
เริ่มเธรดและรอให้เธรดสิ้นสุด นั่นคือเธรดหลักทั่วไปและเธรดลูกอื่น ๆ จะถูกดำเนินการหลังจากสิ้นสุดเธรดหลัก
โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่นข้อยกเว้น {// toDo วิธีที่สร้างขึ้นอัตโนมัติ stub count int int สุดท้าย = 10; countdownlatch finalatch prectElatch = ใหม่ countdownlatch (นับ); // กำหนดจำนวนสลักประตูคือ 10 สำหรับ (int i = 0; i <count; i ++) {เธรด completelatch.countdown (); // ลดหนึ่งประตู latch}}; thread.start ();} completelatch.await (); // ถ้าสลักประตูยังไม่ลดลงรอ -ใน JDK1.4 วิธีการทั่วไปคือการตั้งค่าสถานะของเธรดลูกและการตรวจจับลูปของเธรดหลัก ความสะดวกในการใช้งานและประสิทธิภาพไม่ดี
เริ่มต้นหลายเธรดและรอการแจ้งเตือนเพื่อเริ่มต้น
โมฆะคงที่สาธารณะหลัก (String [] args) พ่นข้อยกเว้น {// toDo วิธีการที่สร้างขึ้นอัตโนมัติ stub final countdownlatch startlatch = new Countdownlatch (1); // define latch ประตูสำหรับ (int i = 0; i <10; i ++) {เธรด = เธรดใหม่ ( ยังลดลงรอ} catch (interruptedException e) {} // do xxxx}}; thread.start ();} startlatch.countdown (); // ลดประตูหนึ่งประตู}Cyclibarrier หลังจากเธรดทั้งหมดถึงบรรทัดเริ่มต้นพวกเขาสามารถทำงานต่อไปได้
Public Class Cyclibarriertest ใช้งาน Runnable {Private Cyclibarrier Barrier; Public Cyclibarriertest (Cyclibarrier Barrier) {this.barrier = barrier;} โมฆะสาธารณะเรียกใช้ () {// do xxxx; ลอง {this.barrier.await () หากคุณไม่มาถึงให้รอต่อไป เมื่อถึงทุกอย่างให้ดำเนินการเนื้อหาของฟังก์ชั่นการทำงานของสิ่งกีดขวาง} catch (Exception e) {}}/** * @param args */โมฆะสาธารณะคงที่หลัก (สตริง [] args) {// พารามิเตอร์ 2 หมายถึงทั้งสองเธรดได้มาถึงบรรทัดเริ่มต้น {// do xxxx;}}); เธรด t1 = เธรดใหม่ (cyclibarriertest ใหม่ (barrier)); เธรด t2 = เธรดใหม่ (cyclibarriertest ใหม่ (สิ่งกีดขวาง)); t1.start (); t2.start ();}}}}}สิ่งนี้ทำให้วิธีการดั้งเดิมในการใช้ฟังก์ชั่นนี้ง่ายขึ้นด้วยตัวนับ + รอ/แจ้งเตือน
10 กฎหมายพร้อมกัน 3 กฎหมาย
กฎหมายของ Amdahl เมื่อพิจารณาจากมาตราส่วนของปัญหาชิ้นส่วนขนานคิดเป็น 12% จากนั้นแม้ว่าจะมีการใช้แบบขนานกับสุดขีดประสิทธิภาพของระบบสามารถปรับปรุงได้โดย 1/(1-0.12) = 1.136 เท่า นั่นคือ: การขนานมีขีด จำกัด สูงสุดในการปรับปรุงประสิทธิภาพของระบบ
กฎหมายของ Gustafson กฎหมายของ Gustafson กล่าวว่ากฎหมายของ Amdahl ไม่ได้พิจารณาว่าสามารถใช้พลังการคำนวณมากขึ้นเมื่อจำนวนซีพียูเพิ่มขึ้น สาระสำคัญคือการเปลี่ยนขนาดของปัญหาเพื่อให้ 88% ที่เหลือของการประมวลผลอนุกรมในกฎหมายของ Amdahl สามารถขนานกันได้ ในสาระสำคัญมันเป็นเวลาแลกเปลี่ยนพื้นที่
กฎหมายซุน-นิ มันเป็นการส่งเสริมเพิ่มเติมของสองกฎหมายแรก แนวคิดหลักคือความเร็วในการคำนวณถูก จำกัด ด้วยความเร็วของการจัดเก็บมากกว่า CPU ดังนั้นเราต้องใช้ประโยชน์จากทรัพยากรการคำนวณอย่างเต็มที่เช่นพื้นที่เก็บข้อมูลและพยายามเพิ่มขนาดของปัญหาเพื่อสร้างโซลูชันที่ดีขึ้น/แม่นยำยิ่งขึ้น
11 จากพร้อมกันถึงคู่ขนาน
คอมพิวเตอร์จำเป็นต้องคำนวณอย่างรวดเร็วเมื่อระบุวัตถุเพื่อให้ชิปร้อนและร้อน เมื่อผู้คนรับรู้วัตถุพวกเขามีความชัดเจนอย่างรวดเร็ว แต่พวกเขาไม่ได้ทำให้เซลล์สมองถูกเผา (เกินจริง) และรู้สึกอึดอัด นี่เป็นเพราะสมองเป็นระบบการทำงานแบบขนานแบบกระจาย เช่นเดียวกับ Google สามารถใช้เซิร์ฟเวอร์ Linux ราคาถูกบางอย่างเพื่อทำการคำนวณที่ซับซ้อนและซับซ้อนเซลล์ประสาทนับไม่ถ้วนในสมองคำนวณอย่างอิสระแบ่งปันผลลัพธ์ซึ่งกันและกันและทำเอฟเฟกต์ที่ต้องใช้การดำเนินการเป็นล้านล้านครั้งสำหรับ CPU เดียว แค่คิดว่าถ้ามันถูกสร้างขึ้นในด้านการประมวลผลแบบขนานมันจะมีผลกระทบที่ไม่สามารถวัดได้ต่อการพัฒนาและอนาคตของคอมพิวเตอร์ แน่นอนความท้าทายสามารถจินตนาการได้: ปัญหามากมายไม่ได้ "แบ่ง" อย่างง่ายดาย
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้เกี่ยวกับปัญหาการเกิดขึ้นพร้อมกันของ Java และฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!