مقدمة: لماذا نحتاج قوائم المهام في Java؟
\n\nكل مطور يواجه عاجلاً أم آجلاً الحاجة لتنظيم معالجة البيانات المتدفقة. تخيل خادم ويب يستقبل آلاف الطلبات في الثانية، أو نظامًا يعالج طلبات متجر إلكتروني. معالجة كل شيء دفعة واحدة أمر مستحيل - الموارد محدودة. هنا تأتي قوائم المهام (task queues) للإنقاذ.
\n\nفي Java، قائمة المهام ليست مجرد هيكل بيانات FIFO (أول دخول، أول خروج). إنها أداة قوية من أجل:
\n- \n
- فصل إنتاج واستهلاك المهام (نمط Producer-Consumer) \n
- إدارة الحمل - تتراكم المهام في القائمة عندما يكون النظام مشغولاً \n
- المعالجة غير المتزامنة - الخيط المنتج لا ينتظر حتى تكتمل المهمة \n
- موازنة التوزيع بين الخيوط - عدة عمال يسحبون المهام من قائمة مشتركة \n
في هذه المقالة، سنستعرض جميع الجوانب الأساسية للعمل مع القوائم في Java: من الواجهات الأساسية لإطار المجموعات Collection Framework إلى القوائم الآمنة للخيوط للتطبيقات متعددة الخيوط.
\n\nالقوائم الأساسية: Queue و Deque
\n\nالواجهة Queue
\n\nالواجهة java.util.Queue هي أساس جميع القوائم في Java. توفر عمليات قياسية للعمل مع القائمة:
| العملية | استثناء عند الخطأ | إرجاع قيمة خاصة |
|---|---|---|
| إضافة | add(e) | offer(e) |
| استخراج وحذف | remove() | poll() |
| عرض (بدون حذف) | element() | peek() |
الفرق بين الطرق واضح: إذا كانت القائمة فارغة، فإن remove() و element() سيرميان NoSuchElementException، بينما poll() و peek() سيعيدان null.
أشهر تطبيقات Queue:
\n- \n
- LinkedList - قائمة مرتبطة مزدوجة، تعمل كقائمة FIFO عادية \n
- PriorityQueue - قائمة ذات أولوية، يتم استخراج العناصر حسب الترتيب المحدد بواسطة Comparator \n
- ArrayDeque - قائمة ثنائية الاتجاه مبنية على مصفوفة \n
مثال: قائمة مهام بسيطة باستخدام LinkedList
\n\nimport java.util.LinkedList;\nimport java.util.Queue;\n\npublic class SimpleTaskQueue {\n public static void main(String[] args) {\n Queue<String> taskQueue = new LinkedList<>();\n\n // إضافة المهام\n taskQueue.offer("تحميل البيانات من قاعدة البيانات");\n taskQueue.offer("إرسال إشعار البريد الإلكتروني");\n taskQueue.offer("إنشاء تقرير");\n\n System.out.println("القائمة: " + taskQueue);\n\n // معالجة جميع المهام\n while (!taskQueue.isEmpty()) {\n String task = taskQueue.poll();\n System.out.println("جارٍ التنفيذ: " + task);\n }\n\n System.out.println("تم تنفيذ جميع المهام!");\n }\n}\n\nالواجهة Deque
\n\nDeque (قائمة مزدوجة النهاية) تسمح بإضافة واستخراج العناصر من كلا الطرفين. هذا يوفر مرونة: يمكن للقائمة أن تعمل كمكدس (LIFO) أو كقائمة عادية (FIFO).
الطرق الأساسية لـ Deque:
\n- \n
addFirst()/offerFirst()- إضافة في البداية \n addLast()/offerLast()- إضافة في النهاية \n removeFirst()/pollFirst()- استخراج من البداية \n removeLast()/pollLast()- استخراج من النهاية \n
مثال: Deque كمكدس للمهام المؤجلة
\n\nimport java.util.ArrayDeque;\nimport java.util.Deque;\n\npublic class DequeExample {\n public static void main(String[] args) {\n De