บทความนี้ส่วนใหญ่พูดถึงคอลเล็กชั่นที่เกี่ยวข้องกับการเกิดขึ้นพร้อมกัน สำหรับคอลเลกชันสามัญโปรดดู [ภาพรวมคอลเลกชัน Java]
1. Blockingqueue คืออะไร
BlockingQueue เป็นคิวการปิดกั้น จากการบล็อกคำจะเห็นได้ว่าการเข้าถึงคิวการบล็อกอาจทำให้เกิดการอุดตันในบางกรณี มีสองกรณีที่ถูกบล็อกหลัก:
1. เมื่อคิวเต็มมันจะถูก enqueued
2. เมื่อคิวว่างเปล่ามันจะออกจากคิว
ดังนั้นเมื่อเธรดพยายามคิวคิวเต็มแล้วมันจะถูกบล็อกเว้นแต่เธรดอื่นจะดำเนินการคิว ในทำนองเดียวกันเมื่อเธรดพยายามคิวคิวที่ว่างเปล่ามันจะถูกบล็อกเว้นแต่เธรดอื่นจะมีการทำงานของคิว
ใน Java อินเทอร์เฟซ BlockingQueue ตั้งอยู่ในแพ็คเกจ java.util.concurrent (มีอยู่ในเวอร์ชัน Java 5) จากลักษณะของคิวการปิดกั้นที่แนะนำข้างต้นจะเห็นได้ว่าคิวการบล็อกนั้นปลอดภัย
2. วิธีใช้ BlockingQueue
การปิดกั้นคิวส่วนใหญ่จะใช้ในสถานการณ์ผู้ผลิต/ผู้บริโภค ภาพต่อไปนี้แสดงการผลิตเธรดและสถานการณ์การบริโภคเธรด:
เธรดที่รับผิดชอบในการผลิตอย่างต่อเนื่องสร้างวัตถุใหม่และแทรกลงในคิวการบล็อกจนกว่าจะถึงขีด จำกัด สูงสุดของคิวนี้ หลังจากคิวมาถึงขีด จำกัด สูงสุดเธรดการผลิตจะถูกบล็อกจนกว่าเธรดที่บริโภคจะใช้คิว ในทำนองเดียวกันเธรดที่รับผิดชอบการบริโภคอย่างต่อเนื่องจะใช้วัตถุอย่างต่อเนื่องจากคิวจนกว่าคิวจะว่างเปล่า เมื่อคิวว่างเปล่าเธรดการบริโภคจะถูกบล็อกเว้นแต่จะมีการใส่วัตถุใหม่ในคิว
3. วิธีการในการปิดกั้นอินเทอร์เฟซ
มีวิธีการสี่ชุดสำหรับการปิดกั้นคิวเพื่อทำการ insert remove และ examine ตามลำดับ เมื่อการดำเนินการที่สอดคล้องกับแต่ละชุดของวิธีการไม่สามารถดำเนินการได้ทันทีจะมีปฏิกิริยาที่แตกต่างกัน ตารางต่อไปนี้แสดงวิธีการเหล่านี้ในลักษณะที่จัดประเภท:
| - | โยนข้อยกเว้น | ค่าพิเศษ | ตึก | เวลาออกไป |
|---|---|---|---|---|
| แทรก | เพิ่ม (o) | ข้อเสนอ (o) | ใส่ (o) | ข้อเสนอ (o, หมดเวลา, TimeUnit) |
| ลบ | ลบ (o) | โพล () | เอา() | โพล (หมดเวลา, TimeUnit) |
| พิจารณา | องค์ประกอบ() | ดู () |
ลักษณะที่สอดคล้องกันของวิธีการทั้งสี่นี้คือ:
1. ThrowSexception: หากการดำเนินการไม่สามารถดำเนินการได้ทันทีข้อยกเว้นจะถูกโยนลงไป
2. SpecialValue: หากการดำเนินการไม่สามารถดำเนินการได้ทันทีค่าพิเศษจะถูกส่งคืนโดยปกติจะเป็นจริงหรือเท็จ
3. บล็อก: หากการดำเนินการไม่สามารถทำได้ทันทีการดำเนินการจะถูกบล็อก
4. TimesOut: หากการดำเนินการไม่สามารถทำได้ทันทีการดำเนินการจะถูกบล็อกในเวลาที่กำหนด หากเวลาที่ระบุไม่ได้ดำเนินการค่าพิเศษจะถูกส่งคืนซึ่งมักจะเป็นจริงหรือเท็จ
ควรสังเกตว่าเราไม่สามารถแทรก null ลงใน blockingqueue มิฉะนั้นจะมีการรายงาน NullPointerException
4. คลาสการใช้งาน BlockingQueue
BlockingQueue เป็นเพียงอินเทอร์เฟซในแพ็คเกจ java.util.concurrent เมื่อใช้มันโดยเฉพาะเราจะใช้คลาสการใช้งาน แน่นอนว่าคลาสการใช้งานเหล่านี้ยังอยู่ในแพ็คเกจ java.util.concurrent ใน Java 6 คลาสการใช้งาน Blockingqueue มีส่วนใหญ่ดังนี้:
1. Arrayblockingqueue
2. delayqueue
3. LinkedBlockingQueue
4. priorityblockingqueue
5. Synchronousqueue
ด้านล่างเราจะแนะนำคลาสการใช้งานเหล่านี้แยกกัน
4.1 arrayblockingqueue
Arrayblockingqueue เป็นคิวการปิดกั้นที่มีขอบเขตและการใช้งานภายในเป็นอาร์เรย์ ความหมายของขอบเขตหมายความว่าความจุของมันมี จำกัด เราต้องระบุขนาดความจุของมันเมื่อเริ่มต้นและขนาดความจุไม่สามารถเปลี่ยนแปลงได้เมื่อมีการระบุ
Arrayblockingqueue จัดเก็บข้อมูลในลักษณะแรกแรก วัตถุที่แทรกใหม่คือหางและวัตถุที่ย้ายออกไปใหม่คือหัว นี่คือตัวอย่างของการเริ่มต้นและการใช้ arrayblockingqueue:
blockingqueue queue = new ArrayblockingQueue (1024); queue.put ("1"); วัตถุวัตถุ = queue.take ();4.2 delayqueue
บล็อกความล่าช้าคือองค์ประกอบภายใน องค์ประกอบใน delayqueue จะต้องใช้อินเตอร์เฟส java.util.concurrent.Delayed คำจำกัดความของอินเทอร์เฟซนี้ง่ายมาก:
อินเทอร์เฟซสาธารณะล่าช้าขยาย <layed> {long getDelay (หน่วย TimeUnit);} ค่าส่งคืนของวิธี getDelay() คือเวลาพักก่อนที่องค์ประกอบคิวจะถูกปล่อยออกมา หาก 0 หรือ负值ถูกส่งคืนหมายความว่าองค์ประกอบหมดอายุและจำเป็นต้องเปิดตัว ในเวลานี้ล่าช้าจะปล่อยวัตถุนี้ผ่านวิธี take()
ดังที่เห็นได้จากคำจำกัดความอินเตอร์เฟสที่ล่าช้าข้างต้นมันยังสืบทอดอินเทอร์เฟซ Comparable นี่เป็นเพราะองค์ประกอบในการล่าช้าจำเป็นต้องจัดเรียง โดยทั่วไปแล้วเราเรียงลำดับตามลำดับความสำคัญของเวลาหมดอายุ
ตัวอย่างที่ 1: ระบุเวลาหมดอายุสำหรับวัตถุ
ก่อนอื่นเรากำหนดองค์ประกอบซึ่งจำเป็นต้องใช้อินเตอร์เฟสที่ล่าช้า
ชั้นเรียนสาธารณะล่าช้าใช้การดำเนินการล่าช้า {ส่วนตัวยาวหมดอายุ; ความล่าช้าส่วนตัว ชื่อสตริงส่วนตัว; DelayEdElement (String ElementName, Long Delay) {สิ่งนี้ ชื่อ = elementName; นี้. ล่าช้า = ล่าช้า; หมดอายุ = (ล่าช้า + ระบบ. currenttimemillis ()); } @Override public int compereto (ล่าช้า o) {ล่าช้า cacheed = (ล่าช้า ledElement) o; return cached.getExpired ()> หมดอายุหรือไม่ 1: -1; } @Override สาธารณะ Long GetDelay (TimeUnit Unit) {return (หมดอายุ - System. currentTimeMillis ()); } @Override สตริงสาธารณะ toString () {return "delayElement [delay =" + delay + ", name =" + name + "]"; } สาธารณะยาว getExpired () {return หมดอายุ; -กำหนดเวลาหมดอายุขององค์ประกอบนี้เป็น 3S
ระดับสาธารณะ DelayQueueExample {โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น InterruptedException {delayQueue <การล่าช้า queue = ใหม่ delayQueue <> (); DelayEdElement ELE = new DelayEdElement ("Cache 3 วินาที", 3000); queue.put (ele); ระบบ. out.println (queue.take ()); -เรียกใช้ฟังก์ชั่นหลักนี้และเราสามารถพบว่าเราต้องรอ 3 วินาทีก่อนที่จะพิมพ์วัตถุนี้
ในความเป็นจริงมีสถานการณ์แอปพลิเคชันมากมายสำหรับการหน่วงเวลาเช่นการเชื่อมต่อปิดที่กำหนดเวลาวัตถุแคชการประมวลผลการหมดเวลาและสถานการณ์อื่น ๆ มาสอบนักเรียนกันเถอะเป็นตัวอย่างเพื่อให้ทุกคนเข้าใจการใช้ความล่าช้าอย่างลึกซึ้งยิ่งขึ้น
ตัวอย่างที่ 2: ปฏิบัติต่อนักเรียนทุกคนในการสอบเป็น delayqueue ใครก็ตามที่จบคำถามก่อนปล่อยพวกเขาก่อน
ก่อนอื่นเราสร้างวัตถุนักเรียน
นักเรียนชั้นเรียนสาธารณะใช้งานได้ล่าช้า {ชื่อสตริงส่วนตัว; // ตั้งชื่อเวลาส่วนตัวส่วนตัว; // เวลาสำหรับคำถามทดสอบเวลาทำงานจริงเวลานาน; // เวลาสำหรับนักเรียนสาธารณะที่เสร็จสมบูรณ์ (ชื่อสตริง, เวลาใช้เวลานาน) {สิ่งนี้ ชื่อ = ชื่อ; นี้. ต้นทุน = ค่าใช้จ่าย; เสร็จสิ้นเวลา = ระบบค่าใช้จ่าย + CurrentTimemillis (); } @Override โมฆะสาธารณะเรียกใช้ () {ระบบ out.println (ชื่อ + "ส่งกระดาษเวลา" + ค่าใช้จ่าย /1000); } @Override สาธารณะ Long GetDelay (TimeUnit Unit) {return (เสร็จสิ้นเวลา - System. currentTimeMillis ()); } @Override public int compereto (ล่าช้า o) {นักเรียนอื่น ๆ = (นักเรียน) o; คืนค่าใช้จ่าย> = อื่น ๆ ค่าใช้จ่าย? 1: -1; -จากนั้นสร้างวัตถุครูเพื่อทำการสอบกับนักเรียน
ครูชั้นเรียนสาธารณะ {Static Final Int Student_size = 30; โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น InterruptedException {สุ่ม r = new random (); // คิดว่านักเรียนทุกคนเป็นความล่าช้าของคิวความล่าช้า <student> นักเรียน = ใหม่ delayqueue <นักเรียน> (); // สร้างพูลเธรดเพื่อให้นักเรียน "ทำการบ้าน" ExecutorService Exec = Executors.NewFixedThreadPool (Student_size); สำหรับ (int i = 0; i <student_size; i ++) {// เริ่มต้นชื่อและเวลาของนักเรียนในการทำแบบทดสอบนักเรียน. บุต (นักเรียนใหม่ ("นักเรียน" + (i + 1), 3000 + r.nextint (10,000))); } // เริ่มต้นการทดสอบในขณะที่ (! students.isempty ()) {exec.execute (นักเรียน. take ()); } exec.shutdown (); -มาดูผลการทำงาน:
นักเรียน 2 ส่งกระดาษ 3
นักเรียน 1 ส่งเอกสารโดยใช้ 5
นักเรียน 5 ส่งกระดาษ 7
นักเรียน 4 ส่งกระดาษรับ 8
นักเรียน 3 ส่งกระดาษ 11
ผ่านผลการดำเนินการเราสามารถพบว่านักเรียนแต่ละคนจะ "ส่งกระดาษ" หลังจากเวลาเริ่มต้นที่กำหนดมาถึง ( ขึ้นอยู่กับวิธี getDelay () ) และกระดาษจะถูกส่งก่อน ( ขึ้นอยู่กับวิธีการเปรียบเทียบ () )
โดยการดูที่ซอร์สโค้ดคุณจะเห็นว่าการใช้งานภายในของ DelayQueue ใช้ PriorityQueue และล็อค:
4.3 LinkedBlockingQueue
การกำหนดค่าของขนาดคิวการปิดกั้น LinkedBlockingQueue เป็นทางเลือก หากเราระบุขนาดเมื่อเริ่มต้นมันจะถูก จำกัด และหากไม่ได้ระบุไว้จะมีขอบเขต มีการกล่าวกันว่าไร้ขอบเขต แต่ในความเป็นจริงขนาดเริ่มต้นคือจำนวนเต็มความจุ Integer.MAX_VALUE การใช้งานภายในเป็นรายการที่เชื่อมโยง
เช่นเดียวกับ ArrayBlockingQueue, LinkedBlockingQueue ยังเก็บข้อมูลในลักษณะแรกแรก วัตถุที่แทรกใหม่คือหางและวัตถุที่ย้ายออกไปใหม่คือหัว นี่คือตัวอย่างของการเริ่มต้นและการสร้าง LinkedBlockingQueue:
BlockingQueue <String> unbounded = new LinkedBlockingQueue <String> (); BlockingQueue <String> bounded = new LinkedBlockingQueue <String> (1024); bounded.put ("value"); ค่าสตริง = bounded.take ();4.4 priorityblockingqueue
Priorityblockingqueue เป็นคิวที่ไม่มีขอบเขตและกฎการเรียงลำดับของมันเหมือนกับ java.util.PriorityQueue ควรสังเกตว่าวัตถุที่เป็นโมฆะได้รับอนุญาตให้แทรกใน priorityblockingqueue
วัตถุทั้งหมดที่แทรกลงใน PriorityBlockingQueue จะต้องใช้อินเตอร์เฟส java.lang.Comparable และกฎการเรียงลำดับลำดับความสำคัญของคิวถูกกำหนดตามการใช้งานอินเทอร์เฟซนี้ของเรา
นอกจากนี้เราสามารถรับตัววนซ้ำจาก priorityblockingqueue แต่ตัววนซ้ำนี้ไม่รับประกันการทำซ้ำตามลำดับความสำคัญ
มายกตัวอย่างเพื่อแสดงให้เห็น ก่อนอื่นเรากำหนดประเภทวัตถุซึ่งจำเป็นต้องใช้อินเทอร์เฟซที่เปรียบเทียบได้:
Public Class PriorityElement ดำเนินการเปรียบเทียบ <criorityElement> {ลำดับความสำคัญของเอกชน; // กำหนดลำดับความสำคัญลำดับความสำคัญ (ลำดับความสำคัญ int) {// เริ่มต้นลำดับความสำคัญนี้ priority = ลำดับความสำคัญ;}@overridepublic int เปรียบเทียบ (ลำดับความสำคัญ o) {// เรียงลำดับ 1: -1;} public int getPriority () {ลำดับความสำคัญคืน;} โมฆะสาธารณะ setPriority (ลำดับความสำคัญ int) {this.priority = priority;}@entridepublic สตริง toString () {return "priorityElement [ลำดับความสำคัญ =" + ลำดับความสำคัญ "]";}}}จากนั้นเราจะตั้งค่าลำดับความสำคัญเป็นคิวแบบสุ่ม
คลาสสาธารณะ PriorityBlockingQueueExample {โมฆะคงที่สาธารณะหลัก (String [] args) พ่น InterruptedException {PriorityBlockingQueue <PriorityElement> QUEUE = ใหม่ PriorityBlockingQueue <> (); สำหรับ (int i = 0; i <5; i ++) {สุ่มสุ่ม = ใหม่สุ่ม (); PriorityElement ELE = new PriorityElement (random.nextint (10)); queue.put (ele); } ในขณะที่ (! queue.isempty ()) {system.out.println (queue.take ()); -ตรวจสอบผลการทำงาน:
PriorityElement [ลำดับความสำคัญ = 3]
PriorityElement [ลำดับความสำคัญ = 4]
PriorityElement [ลำดับความสำคัญ = 5]
PriorityElement [ลำดับความสำคัญ = 8]
PriorityElement [ลำดับความสำคัญ = 9]
4.5 synchronousqueue
อนุญาตให้ใช้องค์ประกอบเดียวภายในคิวแบบซิงโครนัสคิว เมื่อเธรดแทรกองค์ประกอบมันจะถูกบล็อกเว้นแต่ว่าองค์ประกอบจะถูกใช้โดยเธรดอื่น
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น