1. لونغاددر
يتم استخدامه بطريقة مماثلة لـ Atomiclong ، ولكن لديه أداء أفضل من Atomiclong.
يستخدم كل من Longadder و Atomiclong العمليات الذرية لتحسين الأداء. ومع ذلك ، يقوم Longadder بفصل النقطة الساخنة على أساس Atomiclong. يشبه فصل النقطة الساخنة تقليل حجم جسيمات القفل في العملية المقفلة ، مما يفصل القفل إلى عدة أقفال لتحسين الأداء. في خالية من القفل ، يمكن استخدام طرق مماثلة لزيادة معدل نجاح CAS ، وبالتالي تحسين الأداء.
Longadder Schematic:
طريقة تنفيذ Atomiclong هي أن هناك متغير قيمة في الداخل. عندما تكون خيوط متعددة تتزايد ذاتيًا وتناقل ذاتيًا ، يتم تشغيلها جميعًا من مستوى تعليمات الماكينة من خلال تعليمات CAS لضمان ذرة التزامن. السبب الوحيد الذي يقيد كفاءة Atomiclong هو التزامن العالي. يعني التزامن العالي أن CAS لديها فرصة أكبر للفشل ، وأوقات إعادة المحاولة ، والمزيد من الخيوط المحددة ، وارتفاع فرصة فشل CAS ، والتي تصبح دورة مفرغة ، ويتم تقليل كفاءة Atomiclong.
سوف يقوم Longadder بتقسيم القيمة إلى عدة خلايا ، ويضيف جميع الخلايا إلى القيمة. لذلك ، عند إضافة وطرح Longadder ، تحتاج فقط إلى العمل على خلايا مختلفة. الخيوط المختلفة تؤدي عمليات CAS على خلايا مختلفة. بالطبع ، يكون معدل نجاح CAS مرتفعًا (تخيل 3+2+1 = 6 ، مؤشر ترابط واحد 3+1 ، الخيط الآخر 2+1 ، وأخيراً 8 ، لا يحتوي Longadder على واجهة برمجة تطبيقات للتكاثر والانقسام).
ومع ذلك ، عندما لا يكون رقم التزامن مرتفعًا جدًا ، فإن الانقسام إلى عدة خلايا يتطلب أيضًا الحفاظ على الخلية والتلخيص ، وهو ما لا يكون فعالًا مثل تطبيق Atomiclong. استخدم Longadder طريقة ذكية لحل هذه المشكلة.
في الوضع الأولي ، Longadder و Atomiclong هي نفسها. فقط عندما تفشل CAS ، سيتم تقسيم القيمة إلى خلايا. في كل مرة يتم فيها الفشل ، سيتم زيادة عدد الخلايا. هذا هو أيضا فعال في التزامن منخفض. في التزامن العالي ، لن تفشل طريقة المعالجة "التكيفية" بعد الوصول إلى عدد معين من الخلايا ، وسيتم تحسين الكفاءة بشكل كبير.
Longadder هي استراتيجية لتبادل المساحة للوقت.
2. كاملة
قم بتنفيذ واجهة الانتهاء (أكثر من 40 طريقة) ، ومعظمها يستخدم في البرمجة الوظيفية. ودعم مكالمات البث
CompleteFuture هي نسخة محسّنة من المستقبل في Java 8
تطبيق بسيط:
استيراد java.util.concurrent.completableFuture ؛ الطبقة العامة AskThread تنفذ Runnable {complableFuture <integer> re = null ؛ AskThread العام (examblefuture <integer> re) {this.re = re ؛ } Override public void run () {int myre = 0 ؛ حاول {myre = re.get () * re.get () ؛ } catch (استثناء e) {} system.out.println (myre) ؛ } رميات الفراغ الثابتة العامة (سلسلة [] args) interruptedException} موضوع جديد (AskThread (المستقبل)). start () ؛ // محاكاة ترابط عملية حساب طويل الأجل. Sleep (1000) ؛ // أبلغ نتيجة الانتهاء في المستقبل. }} الشيء الأكثر انتقادًا في المستقبل هو أنه يتعين عليك الانتظار والتحقق مما إذا كانت المهمة قد اكتملت من قبل نفسك. في المستقبل ، لا يمكن السيطرة على وقت الانتهاء من المهمة. أكبر تحسن في CompleteFuture هو أن وقت الانتهاء من المهمة مفتوح أيضًا.
Future.complete (60) ؛
تستخدم لتعيين وقت الانتهاء.
التنفيذ غير المتزامن لـ CompleteFuture:
calc integer integer public (integer para) {try {// محاكاة مؤشر ترابط تنفيذ طويل (1000) ؛ } catch (interruptedException e) {} return para * para ؛ } رميات الفراغ الثابتة العامة (String [] args) ، interruptedException ، ExecutionException {Final examblefuture <integer> future = completableFuture .SupplyAsync (() -> calc (50)) ؛ system.out.println (future.get ()) ؛ } دفق الاتصال من قابلية الانتهاء: integer integer calc (integer para) {try {// محاكاة مؤشر ترابط تنفيذ طويل (1000) ؛ } catch (interruptedException e) {} return para * para ؛ } رميات الفراغ الثابتة العامة (السلسلة [] args) interruptedException ، ExecutionException {complableFuture <Void> fu = examberableFuture .SupplyAsync (() -> calc (50)). . fu.get () ؛ }الجمع بين عدة فوتورات:
Calc integer integer public (integer para) {return para / 2 ؛ } رميات الفراغ الثابتة العامة (سلسلة [] args) المقاطعات ، executionException {complableFuture <Void> fu = conferencefuture .supplyasync (() -> calc (50)) .Thencompose ((i) -> examblefuture.supplyasync (() -> calc (i))). "/" ") .Thenaccept (System.out :: println) ؛ fu.get () ؛ } تركز هذه الأمثلة بشكل أكبر على بعض الميزات الجديدة لـ Java 8. فيما يلي بعض الأمثلة لتوضيح الميزات ، لذلك لن أخوضها بعمق.
لا علاقة له بالأداء ، ولكنه أكثر أهمية لدعم البرمجة الوظيفية وتعزيز الوظائف. بالطبع ، إعداد وقت الانتهاء هو تسليط الضوء.
3. Stampedlock
في المقالة السابقة ، تم ذكر فصل القفل للتو ، والتنفيذ المهم لفصل القفل هو ReadWritelock. Stampedlock هو تحسين من ReadWritelock. الفرق بين StampedLock و ReadWritelock هو أن Stampedlock يعتقد أن القراءة يجب ألا تحظر المكتبات ، ويعتقد Stampedlock أنه عندما تكون القراءة والكتابة حصرية بشكل متبادل ، يجب إعادة قراءة القراءة ، بدلاً من السماح لخيط الكتابة بالكتابة. يحل هذا التصميم مشكلة كتابة الجوع في الخيط عند القراءة أكثر والكتابة أقل.
لذلك Stampedlock هو تحسن يميل إلى كتابة المواضيع.
مثال Stampedlock:
استيراد java.util.concurrent.locks.stampedlock ؛ نقطة الطبقة العامة {private double x ، y ؛ Final Final Stampedlock SL = New StampedLock () ؛ move void (Double deltax ، double deltay) {// طريقة طويلة الحصرية Long Stamp = sl.writelock () ؛ حاول {x += deltax ؛ y += deltay ؛ } أخيرًا {sl.UnlockWrite (Stamp) ؛ }} مسافة مزدوجة من fromorigin () {// طريقة طويلة القراءة فقط ختم = sl.TryOpTimisticRead () ؛ double currentx = x ، currenty = y ؛ if (! sl.validate (stamp)) {stamp = sl.readlock () ؛ حاول {currentx = x ؛ Currenty = y ؛ } أخيرًا {sl.unlockRead (Stamp) ؛ }} return math.sqrt (currentx * currentx + currenty * currenty) ؛ }}يحاكي الكود أعلاه مؤشر ترابط الكتابة وخيط القراءة. يتحقق Stampedlock ما إذا كان حصريًا بشكل متبادل وفقًا للختم. عند كتابة ختم مرة واحدة ، يزيد قيمة معينة.
TryoptimisticRead ()
هذا هو الموقف الذي لا تكون فيه القراءة والكتابة حصرية بشكل متبادل كما ذكر.
في كل مرة تقرأ فيها موضوعًا ، ستقوم أولاً بإصدار حكم
إذا (! sl.validate (ختم))
في التحقق من صحة ، سيتحقق أولاً مما إذا كان هناك كتابة مؤشر ترابط الكتابة ، ثم تحديد ما إذا كانت قيمة الإدخال هي نفسها الختم الحالي ، أي تحديد ما إذا كان مؤشر ترابط القراءة سيقرأ أحدث البيانات.
إذا كان هناك كتابة مؤشر ترابط الكتابة ، أو كانت قيمة الطوابع مختلفة ، فإن العائد تفشل.
إذا فشل الحكم ، بالطبع يمكنك محاولة قراءته مرارًا وتكرارًا. في رمز المثال ، لا يُسمح بمحاولة قراءته مرارًا وتكرارًا ، ولكن بدلاً من ذلك يستخدم قفل التفاؤل ليتم تدهوره في أقفال قراءة عادية لقراءتها. هذا الموقف هو طريقة قراءة متشائمة.
ختم = sl.readlock () ؛
فكرة تنفيذ StampedLock:
قفل CLH Spin: عند فشل تطبيق القفل ، لن يتم تعليق مؤشر ترابط القراءة على الفور. سيتم الحفاظ على قائمة انتظار موضوع الانتظار في القفل. جميع المواضيع التي تنطبق على الأقفال ، ولكن لا يتم تسجيل مؤشرات ترابط ناجحة في قائمة الانتظار هذه. كل عقدة (تمثل عقدة واحدة مؤشر ترابط) تحفظ بتات مغلقة لتحديد ما إذا كان مؤشر الترابط الحالي قد أصدر القفل. عندما يحاول مؤشر ترابط الحصول على قفل ، فإنه يحصل على عقدة ذيل قائمة انتظار الانتظار الحالية كعقدة سلفها. واستخدم رموز مثل ما يلي لتحديد ما إذا كانت العقدة المسبقة قد أصدرت القفل بنجاح
بينما (pred.locked) {
}
تتمثل هذه الحلقة في انتظار أن تصدر العقدة السابقة القفل ، بحيث لن يتم تعليق الخيط الحالي بواسطة نظام التشغيل ، وبالتالي تحسين الأداء.
بالطبع ، لن يكون هناك أي يدور لا نهاية له ، وسيتم تعليق الخيط بعد عدة يدور.