Java / المتقدم / الدرس 14
المنفذون والنتائج المؤجلة والإلغاء
صمّم عملاً غير متزامن محدوداً بملكية ونتائج وسياسة مقاطعة وإيقاف واضحة مع مراعاة متطلبات عمر Java17.
في هذه الصفحة
أهداف الدرس
- تمييز إرسال المهمة من اكتمالها.
- تقييد الطوابير وملاحظة الفشل المؤجل.
- تحديد الإلغاء التعاوني وإيقاف المنفذ.
ضع ميزانية للمهام والعمال والسعة التابعة
يفصل المنفذ إرسال المهمة عن سياسة التنفيذ. لا يعني عدد عمال ثابت طابوراً محدوداً؛ تستخدم بعض المصانع طابوراً بلا حد فينمو الانتظار والذاكرة. اختر قبول المهام وسعة الطابور والرفض وحدود التوابع وفق الميزانية. لا يخلق مجمع أكبر سعة قاعدة أو شبكة.
يختلف العمل المعالجي من الإدخال المحجوب في التوازي المناسب. لا تنشئ منفذاً لكل طلب ولا تشارك مجمعاً عاماً بصمت مع حجب غير مرتبط. حدد مالك العمر. ليست ExecutorService في Java17 من AutoCloseable؛ فلا تنسخ مثال إغلاق أحدث دون التحقق من الإصدار.
راقب المهمة عبر Future
تعيد submit نتيجة Future تمثل الاكتمال أو الفشل. تنتظر get وقد تطلق ExecutionException تغلف السبب أو InterruptedException إذا قوطع المنتظر. لا يثبت الحصول على Future نجاح المهمة. يرسل المثال حساباً خالصاً ولا يطبع9 إلا بعد النتيجة.
يغلق العمل التعليمي المحدود المنفذ في finally وينتظر انتهاءه. ترفض shutdown الجديد وتسمح بالمقبول؛ وتحاول shutdownNow المقاطعة وتعيد ما لم يبدأ ولا تجبر أي شيفرة على التوقف الآمن. تحتاج السياسة الفعلية موعداً واستجابة لمهمة تتجاهل المقاطعة أو تحجب بواجهة غير مناسبة.
public class Main {
public static void main(String[] args) throws Exception {
var pool=java.util.concurrent.Executors.newFixedThreadPool(2);
try {
var result=pool.submit(()->3*3);
System.out.println(result.get());
} finally {
pool.shutdown();
if(!pool.awaitTermination(2,java.util.concurrent.TimeUnit.SECONDS)) pool.shutdownNow();
}
}
}
9
تُجلب النتيجة قبل الإغلاق ولا تتبع المهمة مورداً محجوباً خارجياً ولا تترك مجمعاً مملوكاً يعمل.
ركّب النتائج دون حجب خفي
تدعم CompletableFuture تحويل النتائج ودمجها. تحول thenApply قيمة ناجحة وتسطح thenCompose مرحلة تابعة وتجمع thenCombine نتيجتين مستقلتين. افهم هل ينفذ الاستمرار بخيط الإكمال أو نسخة Async بمنفذ؛ تغير الأخيرة الجدولة لا ضرورة ملاحظة الفشل.
يستخدم المثال مراحل مكتملة لعزل دلالة التركيب: يصبح4 ثمانية ثم يضاف3 فينتج11، دون قياس مجمع. تنشر join الفشل بتغليف غير متحقق، ولـget عقد انتظار متحقق. قد تخفي سلسلة منشأة مهملة فشلاً وطلباً غير مكتمل.
public class Main {
public static void main(String[] args) throws Exception {
var result=java.util.concurrent.CompletableFuture.completedFuture(4)
.thenApply(n->n*2)
.thenCombine(java.util.concurrent.CompletableFuture.completedFuture(3),Integer::sum);
System.out.println(result.join());
}
}
11
المراحل مكتملة؛ فيشرح المثال تدفق القيم لا تنفيذها المتوازي أو تسارعها.
عامل المقاطعة كبروتوكول تعاوني
الإلغاء والمقاطعة تعاونيان. قد تطلب Future.cancel(true) المقاطعة لكن على المهمة الاستجابة وإغلاق مواردها. عند التقاط InterruptedException انشرها وفق العقد أو أعد علامة المقاطعة إن تعذر النشر قبل العودة. ابتلاعها والمتابعة إلى الأبد يهدم الإغلاق والمواعيد.
لا تستخدم Thread.stop للإجبار. صمم فحص المقاطعة وعمليات حجب قابلة لها. لا تلغي مهلة انتظار النتيجة المهمة تلقائياً ولا تعكس آثارها. حدد طلب الإلغاء وتأكيد العامل ومصالحة نتيجة خارجية مجهولة.
اختبر الامتلاء والخروج
اختبر النجاح والفشل والإلغاء والامتلاء والإغلاق. تأكد من ملاحظة الفشل وانتهاء العمال ضمن الحد. استخدم مزالج أو متعاوناً مضبوطاً لا النوم لتشكيل التداخل مع مهلة اختبار خارجية تمنع التعليق.
تجنب انتظار مهمة تحتاج المجمع المشبع نفسه؛ فقد ينشأ تجويع أو تعارض دون synchronized. تتبع اعتماد المهام والمجمعات مع الموارد. يظهر التصميم الجيد الملكية والقبول والنتيجة ومعنى المهلة والتنظيف، ولا يجعل الخلفية طريقة لنسيان العمل.
الأخطاء الشائعة وإصلاحها
ExecutionException
- لماذا يحدث؟
- فشلت المهمة وكشفت get سبباً مغلفاً.
- كيف تصلحه؟
- افحص السبب وطبق سياسة العملية.
- كيف تتجنب تكراره؟
- راقب كل نتيجة أو قناة فشل.
RejectedExecutionException
- لماذا يحدث؟
- أُغلق المنفذ أو رفضت سياسة القبول.
- كيف تصلحه؟
- طبق استجابة حمل محددة لا إعادة بلا نهاية.
- كيف تتجنب تكراره؟
- اختبر الإغلاق والامتلاء.
The JVM remains alive after work finishes
- لماذا يحدث؟
- لم ينه مجمع عمال غير خفي مملوك.
- كيف تصلحه؟
- أغلقه وتحقق من الانتهاء بموعد.
- كيف تتجنب تكراره؟
- حدد مالكاً واختبر الخروج.
اختبر فهمك
1. هل تضمن get بمهلة توقف المهمة عند انتهائها؟
اعرض الحل المشروح
لا؛ تحد انتظار المستدعي وقد تستمر المهمة وتؤثر. حدد الإلغاء مستقلاً كتعاون وصالح النتائج الخارجية ولا تفترض المهلة تراجعاً.
2. ترسل مهمة بمجموعة خيط واحد مهمة أخرى إليها وتنتظرها. ما الخطر؟
اعرض الحل المشروح
يحجب العامل الوحيد بانتظار عمل لا يستطيع البدء. أزل الاعتماد الحاجب أو ركب المراحل أو أعد حدود الجدولة. تخفي زيادة الحجم العيب مؤقتاً دون تعليل.
أهم ما تعلمته
- الإرسال ليس اكتمالاً والمهلة ليست إلغاء.
- يحتاج المنفذ حدود قبول ومالك عمر.
- تحتاج المقاطعة سياسة تنظيف تعاونية.