تتحدث هذه المقالة بشكل رئيسي عن المجموعات المشاركة في حزم التزامن. للمجموعات العادية ، يرجى الرجوع إلى [نظرة عامة على مجموعة Java]
1. ما هو blockequeue
Blockingqueue هو قائمة انتظار الحظر. من كلمة حظر ، يمكن ملاحظة أن الوصول إلى قائمة انتظار الحظر قد يتسبب في انسداد في بعض الحالات. هناك حالتان محظورتان رئيسيتان:
1. عندما تكون قائمة الانتظار ممتلئة ، سيتم تنفيذها.
2. عندما تكون قائمة الانتظار فارغة ، ستكون خارج قائمة الانتظار.
لذلك ، عندما يحاول مؤشر ترابط قائمة انتظار قائمة انتظار كاملة بالفعل ، سيتم حظره ما لم يكن مؤشر ترابط آخر عملية قائمة الانتظار ؛ وبالمثل ، عندما يحاول مؤشر ترابط قائمة انتظار قائمة انتظار فارغة ، سيتم حظره ما لم يكن لخيط آخر عملية قائمة الانتظار.
في Java ، تقع واجهة Blockingqueue في حزمة java.util.concurrent (المقدمة في إصدار Java 5). من خصائص قائمة انتظار الحظر التي تم تقديمها أعلاه ، يمكن ملاحظة أن قائمة انتظار الحظر آمنة.
2. كيفية استخدام blockingqueue
تستخدم قوائم انتظار الحظر بشكل أساسي في سيناريوهات المنتج/المستهلك. تعرض الصورة التالية إنتاج مؤشرات الترابط وسيناريو استهلاك مؤشرات الترابط:
يخلق مؤشر الترابط المسؤول عن الإنتاج باستمرار كائنات جديدة وإدراجها في قائمة انتظار الحظر حتى يتم الوصول إلى الحد الأعلى من هذه قائمة الانتظار. بعد وصول قائمة الانتظار إلى الحد الأعلى ، سيتم حظر مؤشر ترابط الإنتاج حتى يستهلك الخيط المستهلك قائمة الانتظار. وبالمثل ، يستهلك الخيط المسؤول عن الاستهلاك باستمرار كائنات من قائمة الانتظار حتى يصبح قائمة الانتظار فارغة. عندما تكون قائمة الانتظار فارغة ، سيتم حظر مؤشر ترابط الاستهلاك ما لم يتم إدخال كائن جديد في قائمة الانتظار.
3. طرق في واجهة blockingqueue
هناك أربع مجموعات من الطرق لحظر قوائم الانتظار لتنفيذ insert remove examine على التوالي. عندما لا يمكن تنفيذ العمليات المقابلة لكل مجموعة من الأساليب على الفور ، ستكون هناك ردود فعل مختلفة. يسرد الجدول التالي هذه الطرق بطريقة مصنفة:
| - | رمي الاستثناء | قيمة خاصة | كتل | مرات في الخارج |
|---|---|---|---|---|
| أدخل | إضافة (س) | عرض (س) | ضع (س) | عرض (يا ، مهلة ، الوقت المحدد) |
| يزيل | إزالة (س) | استطلاع () | يأخذ() | استطلاع (مهلة ، الوقت المحدد) |
| يفحص | عنصر() | نظرة خاطفة () |
الخصائص المقابلة لهذه المجموعات الأربع من الأساليب هي:
1.
2. القيمة الخاصة: إذا كان لا يمكن إجراء العملية على الفور ، فسيتم إرجاع قيمة خاصة ، عادة صحيحة أو خاطئة
3. الكتل: إذا كان لا يمكن إجراء العملية على الفور ، فسيتم حظر العملية
4. مرة: إذا كان لا يمكن تنفيذ العملية على الفور ، فسيتم حظر العملية في الوقت المحدد. إذا لم يتم تنفيذ الوقت المحدد ، فسيتم إرجاع قيمة خاصة ، والتي عادة ما تكون صحيحة أو خاطئة.
تجدر الإشارة إلى أننا لا نستطيع إدراج null في blockingqueue ، وإلا سيتم الإبلاغ عن NullPointerException .
4. فئة تنفيذ Plockingqueue
Plockingqueue هي مجرد واجهة في حزمة java.util.concurrent . عند استخدامه على وجه التحديد ، نستخدم فئات التنفيذ الخاصة به. بالطبع ، توجد فئات التنفيذ هذه أيضًا في حزمة java.util.concurrent . في Java 6 ، تكون فصول تنفيذ Blockingqueue أساسًا على النحو التالي:
1. arrayblockingqueue
2. تأخير
3. LinkedBlockingqueue
4
5. متزامن
أدناه سنقدم فئات التنفيذ هذه بشكل منفصل.
4.1 arrayblockingqueue
ArrayBlockingqueue هو قائمة انتظار حظر محددة ، وتنفيذها الداخلي هو صفيف. يعني معنى الحدود أن قدرتها محدودة ، يجب علينا تحديد حجم سعةها عند تهيئتها ، ولا يمكن تغيير حجم السعة بمجرد تحديده.
يقوم ArrayBlockingQueue بتخزين البيانات بطريقة أولى في الأول. الكائن الذي تم إدخاله حديثًا هو الذيل والكائن الذي تم نقله حديثًا هو الرأس. فيما يلي مثال على تهيئة واستخدام ArrayBlockingQueue:
قائمة انتظار blockingqueue = جديد arrayblockingqueue (1024) ؛ queue.put ("1") ؛ Object Object = queue.take () ؛4.2 تأخير
ما هي كتل تأخير هي عناصرها الداخلية. يجب أن تنفذ العناصر الموجودة في تأخير java.util.concurrent.Delayed . تعريف هذه الواجهة بسيط للغاية:
تمتد الواجهة العامة المتأخرة المماثلة <gended> {Long GetDelay (وحدة TimeUnit) ؛} قيمة الإرجاع لطريقة getDelay() هي وقت الانتظار قبل إصدار عنصر الانتظار. إذا تم إرجاع 0 أو负值، فهذا يعني أن العنصر قد انتهى ويجب إصداره. في هذا الوقت ، ستقوم شركة تأخير بإطلاق هذا الكائن من خلال طريقة take() .
كما يتضح من تعريف الواجهة المتأخرة أعلاه ، فإنه يرث أيضًا الواجهة Comparable . وذلك لأن العناصر الموجودة في التأخير تحتاج إلى فرز. بشكل عام ، نفرز أولوية وقت انتهاء صلاحية العنصر.
مثال 1: حدد وقت انتهاء الصلاحية لكائن ما
أولاً ، نحدد عنصرًا يحتاج إلى تنفيذ الواجهة المتأخرة
تأخرت الطبقة العامة تأخر تأخر {private منذ فترة طويلة ؛ تأخير طويل خاص ؛ اسم السلسلة الخاصة ؛ تأخير (elementname string ، تأخير طويل) {هذا. الاسم = elementName ؛ هذا. التأخير = التأخير ؛ منتهية الصلاحية = (تأخير + نظام. CurrentTimeMillis ()) ؛ } Override public int compareto (تأخر o) {adgrentedElement cached = (تأخير) o ؛ العودة cached.getExpired ()> انتهت صلاحية؟ 1: -1 ؛ } Override Public Long GetDelay (وحدة TimeUnit) {return (منتهية الصلاحية - النظام. CurrentTimeMillis ()) ؛ } Override public string toString () {return "develededElement [delay =" + delay + "، name =" + name + "]" ؛ } public long getExpired () {return انتهت صلاحية ؛ }}اضبط وقت انتهاء صلاحية هذا العنصر على 3s
فئة Public Class DelayQueexample {public static void main (string [] args) remrows interruptedException {delayqueue <GindedElement> Queue = New DelayQueue <> () ؛ EleedElement ELE = تأخير جديد ("ذاكرة التخزين المؤقت 3 ثوان" ، 3000) ؛ Queue.put (eLe) ؛ نظام. Out.println (queue.take ()) ؛ }}قم بتشغيل هذه الوظيفة الرئيسية ويمكننا أن نجد أننا بحاجة إلى الانتظار 3 ثوان قبل طباعة هذا الكائن.
في الواقع ، هناك العديد من سيناريوهات التطبيق للتأخير ، مثل اتصالات الإغلاق المحددة ، وكائنات ذاكرة التخزين المؤقت ، ومعالجة المهلة وغيرها من السيناريوهات. دعنا نأخذ امتحان الطالب كمثال للسماح للجميع بفهم استخدام التأخير بشكل أعمق.
مثال 2: عامل جميع الطلاب في الامتحان على أنه تأخير ، أي شخص ينهي الأسئلة أولاً
أولاً ، نقوم ببناء كائن طالب
طالب الفئة العامة ينفذ Runnable ، المتأخر {اسم السلسلة الخاصة ؛ // اسم التكلفة الطويلة الخاصة ؛ // حان الوقت للاختبار أن الوقت قد انتهى منذ فترة طويلة ؛ // حان الوقت لإكمال الطالب العام (اسم السلسلة ، الوقت الطويل) {هذا. الاسم = الاسم ؛ هذا. COSTTIME = COSTTIME ؛ HINGTIME = COSTTIME + نظام. CurrentTimeMillis () ؛ } Override public void run () {system. out.println (الاسم + "إرسال الورقة ، الوقت" + COSTTIME /1000) ؛ } Override Public Long GetDelay (وحدة TimeUnit) {return (HISTTIME - SYSTEM. } Override public int compareto (تأخير o) {student Other = (student) o ؛ الإرجاع COSTTIME> = آخر. COSTTIME؟ 1: -1 ؛ }}ثم ، قم ببناء كائن معلم لأخذ الامتحان للطلاب
مدرس الفصل العام {Static Final int student_size = 30 ؛ الفراغ الثابت العام (سلسلة [] args) يلقي InterruptedException {Random R = new Random () ؛ // فكر في جميع الطلاب على أنه تأخير قائمة انتظار التأخير <Tudents> الطلاب = تأخير جديد <Tudentique> () ؛ . لـ (int i = 0 ؛ i <student_size ؛ i ++) {// قم بتهيئة اسم الطالب ووقت إجراء طلاب الاختبار. } // ابدأ الاختبار بينما (! students.isempty ()) {exec.execute (students.take ()) ؛ } exec.shutdown () ؛ }}لنلقي نظرة على نتائج الجري:
الطالب 2 أرسل الورقة ، 3
الطالب 1 يسلم في الأوراق ، يأخذ 5
الطالب 5 أرسل الورقة ، 7
الطالب 4 يقدم الورقة ، وأخذ 8
الطالب 3 يقدم الورقة ، 11
من خلال نتائج التشغيل ، يمكننا أن نجد أن كل طالب سيقوم "بإرسال الورقة" بعد وصول وقت البدء المحدد ( اعتمادًا على طريقة getDelay () ) ، وسيتم تقديم الورقة أولاً ( اعتمادًا على طريقة المقارنة () ).
من خلال النظر إلى رمز المصدر الخاص به ، يمكنك أن ترى أن التنفيذ الداخلي للتأخير يستخدم الأولوية وقفل:
4.3 LinkedBlockingqueue
يعد تكوين حجم قائمة انتظار حظر LinkedBlockingQueue اختياريًا. إذا حددنا حجمًا عند التهيئة ، فسيكون محددًا ، وإذا لم يتم تحديده ، فسيكون محدودًا. يقال إنه لا حدود له ، ولكن في الواقع ، فإن الحجم الافتراضي هو Integer.MAX_VALUE سعة. تنفيذها الداخلي هو قائمة مرتبطة.
مثل ArrayBlockingQueue ، تقوم LinkedBlockingQueue أيضًا بتخزين البيانات بطريقة الأولى في الأول. أحدث كائن تم إدخاله هو الذيل وأحدث كائن تم نقله هو الرأس. فيما يلي مثال على التهيئة وجعل LinkedBlockingQueue:
blockingqueue <string> unbounded = new LinkedBlockingQueue <string> () ؛ blockingqueue <string> bound = new LinkedBlockingQueue <string> (1024) ؛ bound.put ("value")4.4 PriorityBlockingqueue
PriorityBlockingQueue هي قائمة انتظار بدون حدود ، وقواعد الفرز الخاصة بها هي نفسها java.util.PriorityQueue . تجدر الإشارة إلى أنه يُسمح بإدراج الكائنات الفارغة في PriorityBlockingQueue.
يجب أن تنفذ جميع الكائنات التي تم إدراجها في priorityblockingqueue واجهة java.lang.Comparable ، ويتم تحديد قواعد فرز أولوية قائمة الانتظار وفقًا لتنفيذنا لهذه الواجهة.
بالإضافة إلى ذلك ، يمكننا الحصول على مؤلف من PriorityBlockingQueue ، ولكن هذا التكرار لا يضمن التكرار في ترتيب الأولوية.
دعنا نعطي مثالا لتوضيح. أولاً ، نحدد نوع كائن ، والذي يحتاج إلى تنفيذ الواجهة المماثلة:
Publity PriorityElement تنفس قابلة للمقارنة <prolexelement> {private int priority ؛ // تحديد الأولوية ذات الأولوية (int priority) {// تهيئة الأولوية this.priority = priority ؛}@@overridepublic int compareto (priorityelement o) {// sort by properitial size repirit> = o.getPriority ()؟ 1: -1 ؛} public int getPriority () {return priority ؛} public void setPriority (int priority) {this.priority = priority ؛}@Overridepublic String ToString () {return "priorityelement [priority =" + priority + "]" ؛}}}}ثم نضع الأولوية بشكل عشوائي على قائمة الانتظار
الطبقة العامة priorityblockingqueueeexample {public static void main (string [] args) remrows interruptedException {priorityBlockingQueue <PrialityElement> Queue = new PriorityBlockingQueue <> () ؛ لـ (int i = 0 ؛ i <5 ؛ i ++) {عشوائي عشوائي = جديد عشوائي () ؛ priorityElement eLe = priorityElement جديد (Random.NextInt (10)) ؛ Queue.put (eLe) ؛ } بينما (! queue.isempty ()) {system.out.println (queue.take ()) ؛ }}}تحقق من نتائج التشغيل:
الأولوية [الأولوية = 3]
الأولوية [الأولوية = 4]
الأولوية [الأولوية = 5]
الأولوية [الأولوية = 8]
الأولوية [الأولوية = 9]
4.5 متزامن
يُسمح عنصرًا واحدًا فقط داخل قائمة انتظار متزامنة. عندما يقوم مؤشر ترابط بإدخال عنصر ما ، سيتم حظره ما لم يتم استهلاك العنصر بواسطة مؤشر ترابط آخر.
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.