قدَّم:
منذ بعض الوقت ، ذهبت إلى البنك للتعامل مع الأعمال التجارية ، وكان هناك الكثير من الناس في الطابور. استغرق الأمر أقل من 5 دقائق للتعامل مع العمل بنفسي ، لكنني انتظرت لمدة ساعتين (أعتقد أن الكثير من الناس واجهوا هذا الموقف). كنت عاجزًا عن الكلام حول مستوى الخدمة هذا ، لكن المشكلة تنشأ مرة أخرى. يجب على البنك فتح العديد من النوافذ لضمان جودة الخدمة الإجمالية ومعدل استخدام الموارد؟ بعد ذلك ، سنحاكي هذه المشكلة من خلال نظرية قائمة الانتظار.
مقدمة لنظرية قائمة الانتظار
نظرية قائمة الانتظار هي نظرية وطريقة رياضية تدرس ظاهرة التجمع العشوائي وتشتت الأنظمة وهندسة العمل للأنظمة العشوائية. يُعرف أيضًا باسم نظرية أنظمة الخدمة العشوائية ، وهو فرع لأبحاث العمليات. دعنا نبسيط نظرية قائمة الانتظار أدناه ، وننظر إلى الشكل التالي أولاً:
نرتب العديد من مكاتب الخدمة الزرقاء على الجانب الأيسر من الصورة ، مع العملاء الأحمر الذين قد يأتون على اليمين ، ومنطقة انتظار صفراء في الوسط. إذا كان مكتب الخدمة في وضع الخمول ، فيمكن للعملاء تلقي الخدمات مباشرة ، وإلا يجب عليهم الانتظار في المنطقة الصفراء. يتبنى ترتيب خدمة العملاء مبدأ الخدمة الأولى والخدمة الحالية. الآن إذا عرفنا توزيع احتمال قادم العملاء ، فكيف يمكننا ترتيب العديد من مكاتب الخدمة على اليسار لتحقيق مستوى خدمة أفضل وضمان معدل استخدام مكتب الخدمة؟ بعد ذلك ، سنقوم ببناء نموذج لمحاكاة هذه المشكلة.
يتم تنفيذ نظرية قائمة الانتظار خطوة بخطوة
1) بالنسبة لنظرية قائمة الانتظار ، نحتاج أولاً إلى تحديد سمات العميل ، ومعرفة متى يصل العميل ، ووقت الخدمة المطلوب ، وما إلى ذلك. نقوم أولاً بإنشاء فصل عميل ، حيث نحدد الحد الأقصى والحد الأدنى لخدمة العملاء. هنا ، من أجل التبسيط ، نعتقد بشكل مباشر أن وقت الخدمة عشوائي تمامًا:
الطبقة العامة CustomerBean {// الحد الأدنى لوقت الخدمة الخاص ثابت int minservetime = 3 * 1000 ؛ // الحد الأقصى لوقت الخدمة الخاص ثابت int maxservetime = 15 * 1000 ؛ // العميل يصل إلى الوقت الخاص بالوقت الطويل ؛ // يحتاج العميل إلى وقت الخدمة الخاص بالخدمة الخاصة ؛ العميل العام () {// ضبط وقت الوصول arrival = system.currentTimeMillis () ؛ // SET Random SET SERVETIME = (int) (Math.Random () * (MaxServetime - minservetime) + minservetime) ؛ }} 2) نحدد العميل أعلاه ، ثم نحتاج إلى تحديد قائمة انتظار قائمة انتظار. دعونا نلقي نظرة أولاً على سمات قائمة الانتظار. هنا نحدد صفيفًا لإنقاذ عملاء قائمة الانتظار ، وتحديد الفواصل الزمنية الدنيا والحد الأقصى للوصول إلى العميل التالي وتوصل احتمال قادم العميل (ليتم شرحه لفترة وجيزة هنا ، إذا كان الوقت الفاصل الزمني للعميل التالي هو 3 ، ولكن يتم حسابها من خلال السوقة الممكنة من خلال السوقية ، ويلتزم العميل بالرضا.
ClientQuene ClientQuene {// في انتظار قائمة انتظار العملاء الخاصة بـ LinkedList <PustomerBean> العملاء = New LinkedList <PustomerBean> () ؛ // أقصر وقت للعميل التالي ليأتي private int mintime = 0 ؛ // الحد الأقصى للوقت للعميل التالي ليأتي int maxtime = 1 * 1000 ؛ . // تحديد ما إذا كان العميل الخاص بالعلم المنطقي = صحيح ؛ // الحد الأقصى لعدد الأشخاص الذين يصطفون في طوابير int maxwaitnum الخاصة = 0 ؛ } 3) عندما يكون هناك عملاء وقوائم الانتظار ، قمنا بإعداد موضوع لإنشاء العملاء لإنشاء العملاء باستمرار. فيما يلي توزيعات الوقت والاحتمالات التي ذكرناها أعلاه.
/ ***@الوصف: إنشاء مؤشر ترابط العميل*@الإصدار: 1.1.0*/ private clustythread يمتد Thread {Private CustomerThread (اسم السلسلة) {super (name) ؛ } Override public void run () {بينما (flag) {// أضف عميلًا جديدًا في نهاية الفريق if (math.random () <rate) {clients.addlast (new customerbean ()) ؛ if (maxwaitnum <clients.size ()) {maxwaitnum = clients.size () ؛ }} int sleeptime = (int) (math.random () * (maxtime - mintime) + mintime) ؛ جرب {timunit.milliseconds.sleep (النوم) ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ }}}}} 4) إذا كان هناك عملاء في قائمة الانتظار في قائمة الانتظار لقطع مكتب الخدمة المجاني ، فأنت بحاجة إلى الحصول على العميل في رأس الفريق لتلقي الخدمة.
Customerbean getCustomerBean () {if (عملاء == null || clients.size () <1) {return null ؛ } إرجاع العملاء. removefirst () ؛ } 5) السمات والأساليب المتعلقة بالعملاء كلها جاهزة. دعنا نضع سمات مكتب الخدمة المتعلقة. هنا قمنا بتعيين مكتب الخدمة مباشرة على موضوع لتحديد بعض مؤشرات الخدمة ، مثل عدد العملاء الذين يتم تقديمهم ، وإجمالي وقت الانتظار ، وإجمالي وقت الخدمة ، وأقصى وقت انتظار ، إلخ.
يمتد ServantTherThread من الفئة العامة Thread {// عدد عملاء الخدمة الثابتة int customernum = 0 ؛ // إجمالي وقت الانتظار الخاص ثابت int sumwaittime = 0 ؛ // إجمالي وقت الخدمة static int sumservetime = 0 ؛ // الحد الأقصى لوقت الانتظار الخاص ثابت int maxwaittime = 0 ؛ العلم المنطقي الخاص = خطأ ؛ اسم السلسلة الخاصة ؛ } 6) الوظيفة الرئيسية لمكتب الخدمة هي خدمة العملاء. هنا نكتب العمليات المتعلقة بخدمة العملاء في طريقة تشغيل الموضوع.
public void run () {flag = true ؛ بينما (flag) {customerBean customer = customerquene.getCustomerQuene (). getCustomerBean () ؛ // إذا تم إغلاق مؤشر ترابط العميل ولم يكن هناك عملاء في قائمة الانتظار ، فإن مؤشر ترابط مكتب الخدمة يغلق وإصدار إذا (العميل == null) {if (! customerquene.getCustomerQuene (). isFlag ()) {flag = false ؛ مطبعة()؛ } يكمل؛ } طويلًا الآن = system.currentTimeMillis () ؛ int waittime = (int) (الآن - customer.getArrivetime ()) ؛ // احفظ الحد الأقصى لوقت الانتظار إذا (waittime> maxwaittime) {maxwaittime = waittime ؛ } // وقت النوم هو وقت خدمة العميل ، والذي يمثل فترة الخدمة خلال هذه الفترة الزمنية التي تخدم العملاء. حاول {timunit.milliseconds.sleep (customer.getServetime ()) ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ } system.err.println (name + "الوقت لخدمة العملاء:" + customer.getServeservetime () + "MS/T Customer Waiting:" + Waittime + "MS") ؛ customernum ++ ؛ sumwaittime += waittime ؛ sumServetime += customer.getServetime () ؛ }} 7) أخيرًا ، نكتب نموذج اختبار للتحقق من مستوى الخدمة
/ ** *@الوصف: */ package com.lulei.opsearch.quene ؛ استيراد java.util.concurrent.timeunit ؛ اختبار الفئة العامة {public static void main (string [] args) {// افتح system.out.println ("افتح الباب والتقاط العملاء!") ؛ العلم المنطقي = صحيح ؛ customerquene.getCustomerQuene () ؛ long a = system.currentTimeMillis () ؛ int servicenum = 10 ؛ لـ (int i = 0 ؛ i <servicenum ؛ i ++) {servantThread thread = new servantThRead ("Service Desk"+i) ؛ thread.start () ؛ } بينما (flag) {long b = system.currentTimeMillis () ؛ if (b - a> 1 * 60 * 1000 && flag) {// flag flag = false ؛ customerquene.getCustomerQuene (). close () ؛ System.out.println ("أغلق الباب ولا تلتقط العملاء!") ؛ } system.out.println ("وقت تشغيل النظام:" + (b -a) + "MS") ؛ system.out.println ("نظام الخمول:" + ((b -a) * servantnum - servantThread.getSumServetime ()))) ؛ servantTherD.Print () ؛ جرب {timeUnit.Seconds.sleep (2) ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ }}}} نتائج التشغيل
1) بدء التشغيل
2) يولد العميل إغلاق الموضوع
3) مستوى الخدمة النهائية
من خلال تعديل عدد مكاتب الخدمة ، يمكنك تقييم عدد مكاتب الخدمة التي يجب إعدادها في وضع العميل الحالي.
رمز كامل
1) فئة العميل
/ ** *@الوصف: */ package com.lulei.opsearch.quene ؛ الطبقة العامة CustomerBean {// الحد الأدنى لوقت الخدمة الخاص ثابت int minservetime = 3 * 1000 ؛ // الحد الأقصى لوقت الخدمة الخاص ثابت int maxservetime = 15 * 1000 ؛ // العميل يصل إلى الوقت الخاص بالوقت الطويل ؛ // يحتاج العميل إلى وقت الخدمة الخاص بالخدمة الخاصة ؛ العميل العام () {// ضبط وقت الوصول arrivetime = system.currentTimeMillis () ؛ . } static int getMinServetime () {return minservetime ؛ } public static void setMinServetime (int minservetime) {customerbean.minservetime = minservetime ؛ } static int getMaxServetime () {return maxServetime ؛ } public static void setMaxServetime (int maxServetime) {customerBean.MaxServetime = maxServetime ؛ } public long getarrivetime () {return arrivetime ؛ } public void setarrivetime (long envetime) {this.arrivetime = envetime ؛ } public int getServetime () {return servetime ؛ } public void setServetime (int servetime) {this.servetime = servetime ؛ }}2) قائمة انتظار العملاء
/ ** *@الوصف: */ package com.lulei.opsearch.quene ؛ استيراد java.util.linkedList ؛ استيراد java.util.concurrent.timeunit ؛ ClientQuene ClientQuene {// في انتظار قائمة انتظار العملاء الخاصة بـ LinkedList <PustomerBean> العملاء = New LinkedList <PustomerBean> () ؛ // أقصر وقت للعميل التالي ليأتي private int mintime = 0 ؛ // الحد الأقصى للوقت للعميل التالي ليأتي int maxtime = 1 * 1000 ؛ // احتمال قادم العميل المعدل المزدوج = 0.9 ؛ // تحديد ما إذا كان العملاء يواصلون توليد علم منطقي خاص = صحيح ؛ // الحد الأقصى لعدد الأشخاص في قائمة انتظار int maxwaitnum = 0 ؛ public int getMaxWaitNum () {return maxwaitnum ؛ } boolean public iSflag () {return flag ؛ } / ** * return * author: lulei * description: احصل على العميل في رأس قائمة الانتظار * / customerbean getCustomerBean () {if (العملاء == null || العملاء. } إرجاع العملاء. removefirst () ؛ } public void close () {if (flag) {flag = false ؛ }} / ** * return * author: lulei * description: احصل على عدد عملاء الانتظار * / public int getWaitCustomerNum () {return clients.size () ؛ } / ***@الوصف: إنشاء مؤشر ترابط العميل*@الإصدار: 1.1.0* / Private ClustyThread يمتد Thread {Private CustomerThread (اسم السلسلة) {super (name) ؛ } Override public void run () {بينما (flag) {// أضف عميلًا جديدًا في نهاية الفريق if (math.random () <rate) {clients.addlast (new customerbean ()) ؛ if (maxwaitnum <clients.size ()) {maxwaitnum = clients.size () ؛ }} int sleeptime = (int) (math.random () * (maxtime - mintime) + mintime) ؛ جرب {timunit.milliseconds.sleep (النوم) ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ }}}}} // Singleton Mode ابدأ من فئة ثابتة خاصة customerquenedao {private static customerquene customerquene = new customerquene () ؛ } customerQuene الخاص () {customerThread CustomerThread = جديد CustomerThread ("Thread Generation Customer") ؛ customerthread.start () ؛ } العميل الثابت العام getCustomerQuene () {return customerquenedao.customerquene ؛ } // Singleton Mode End Public int getMintime () {return mintime ؛ } public void setMintime (int mintime) {this.mintime = mintime ؛ } public int getMaxTime () {return maxtime ؛ } public void setMaxTime (int maxtime) {this.maxtime = maxtime ؛ } public double getRate () {return rate ؛ } public void setRate (معدل مزدوج) {this.rate = rate ؛ }} 3) موضوع مكتب الخدمة
/ ** *@الوصف: */ package com.lulei.opsearch.quene ؛ استيراد java.util.concurrent.timeunit ؛ استيراد com.lulei.util.parseutil ؛ يمتد ServantTherThread من الفئة العامة Thread {// عدد عملاء الخدمة الثابتة int customernum = 0 ؛ // إجمالي وقت الانتظار الخاص ثابت int sumwaittime = 0 ؛ // إجمالي وقت الخدمة static int sumservetime = 0 ؛ // الحد الأقصى لوقت الانتظار الخاص ثابت int maxwaittime = 0 ؛ العلم المنطقي الخاص = خطأ ؛ اسم السلسلة الخاصة ؛ الموظف العام (اسم السلسلة) {super (name) ؛ this.name = name ؛ } static int getMaxWaittime () {return maxwaittime ؛ } int static int getSumServetime () {return sumservetime ؛ } Override public void run () {flag = true ؛ بينما (flag) {customerBean customer = customerquene.getCustomerQuene (). getCustomerBean () ؛ // إذا تم إغلاق مؤشر ترابط العميل ولم يكن هناك عملاء في قائمة الانتظار ، فإن مؤشر ترابط مكتب الخدمة يغلق وإصدار إذا (العميل == null) {if (! customerquene.getCustomerQuene (). isFlag ()) {flag = false ؛ مطبعة()؛ } يكمل؛ } طويلًا الآن = system.currentTimeMillis () ؛ int waittime = (int) (الآن - customer.getArrivetime ()) ؛ // احفظ الحد الأقصى لوقت الانتظار إذا (waittime> maxwaittime) {maxwaittime = waittime ؛ }. } catch (استثناء e) {E.PrintStackTrace () ؛ } system.err.println (name + "الوقت لخدمة العملاء:" + customer.getServetime () + "MS/T Customer Waiting:" + Waittime + "MS") ؛ customernum ++ ؛ sumwaittime += waittime ؛ sumServetime += customer.getServetime () ؛ }} print print print () {if (customernum> 0) { System.out.println ("-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // إخراج متوسط وقت الانتظار للعميل ، والاحتفاظ بمكانين عشريين. Customernum) ، 2) "MS") ؛ 4) اختبار النموذج
/ ** *@الوصف: */ package com.lulei.opsearch.quene ؛ استيراد java.util.concurrent.timeunit ؛ اختبار الفئة العامة {public static void main (string [] args) {// افتح system.out.println ("افتح الباب والتقاط العملاء!") ؛ العلم المنطقي = صحيح ؛ customerquene.getCustomerQuene () ؛ long a = system.currentTimeMillis () ؛ int servicenum = 10 ؛ لـ (int i = 0 ؛ i <servicenum ؛ i ++) {servantThread thread = new servantThRead ("Service Desk"+i) ؛ thread.start () ؛ } بينما (flag) {long b = system.currentTimeMillis () ؛ if (b - a> 1 * 60 * 1000 && flag) {// flag flag = false ؛ customerquene.getCustomerQuene (). close () ؛ System.out.println ("أغلق الباب ولا تلتقط العملاء!") ؛ } system.out.println ("وقت تشغيل النظام:" + (b -a) + "MS") ؛ system.out.println ("نظام الخمول:" + ((b -a) * servantnum - servantThread.getSumServetime ()))) ؛ servantTherD.Print () ؛ جرب {timeUnit.Seconds.sleep (2) ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ }}}}ما سبق هو مقدمة مفصلة لمبادئ تنفيذ Java تنفيذ نظرية قائمة الانتظار. آمل أن يكون ذلك مفيدًا لتعلم الجميع.