قوائم المهام في Java: دليل عملي مع أمثلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا نحتاج قوائم المهام في Java؟

\n\n

في التطوير الحديث باستخدام Java، تعدد الخيوط ليس رفاهية بل ضرورة. التطبيقات تعالج آلاف الطلبات، وتنفذ مهام الخلفية، وتتفاعل مع الخدمات الخارجية. بدون تنظيم صحيح لقوائم المهام، يتحول الكود إلى فوضى: تمنع الخيوط بعضها البعض، وتمتلئ الذاكرة، وينخفض الأداء.

\n\n

قوائم المهام (Task Queues) هي آلية تسمح بتوزيع العمل بكفاءة بين الخيوط. في Java، توجد مجموعة أدوات قوية في الحزمة java.util.concurrent. في هذه المقالة، سنشرح كيفية استخدام قوائم المهام عمليًا، مع أمثلة كود حقيقية.

\n\n

ستتعلم:

\n
    \n
  • كيف تعمل BlockingQueue وتطبيقاتها
  • \n
  • كيفية إعداد ThreadPoolExecutor لمهام محددة
  • \n
  • كيفية تجنب الأخطاء الشائعة عند العمل مع القوائم
  • \n
  • كيفية اختبار وتصحيح كود تعدد الخيوط
  • \n
\n\n

أساسيات قوائم المهام: BlockingQueue

\n\n

BlockingQueue هي واجهة تشكل أساس معظم قوائم المهام في Java. تدعم عمليات الانتظار: إذا كانت القائمة فارغة، ينتظر الخيط المستهلك حتى يظهر عنصر؛ إذا كانت القائمة ممتلئة، ينتظر الخيط المنتج حتى يتوفر مكان.

\n\n

التطبيقات الرئيسية لـ BlockingQueue

\n\n

في Java، توجد عدة تطبيقات لـ BlockingQueue، لكل منها خصائصه:

\n\n
    \n
  • ArrayBlockingQueue — حجم ثابت، مبني على مصفوفة. مناسب للسيناريوهات ذات الحد المعروف للمهام.
  • \n
  • LinkedBlockingQueue — محدودة اختياريًا، مبنية على قائمة مرتبطة. جيدة للأحمال الديناميكية.
  • \n
  • PriorityBlockingQueue — قائمة غير محدودة ذات أولويات. تُستخدم عندما تكون للمهام أهمية مختلفة.
  • \n
  • SynchronousQueue — قائمة بدون سعة: كل insert يجب أن ينتظر remove المقابل. مثالية للنقل المباشر للمهام.
  • \n
\n\n

مثال: قائمة مهام بسيطة مع ArrayBlockingQueue

\n\n

لننظر إلى مثال أساسي حيث يقوم خيط بتوليد المهام وآخر بمعالجتها:

\n\n
import java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\n\npublic class SimpleTaskQueue {\n    public static void main(String[] args) {\n        BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);\n\n        // خيط منتج\n        Thread producer = new Thread(() -> {\n            try {\n                for (int i = 1; i <= 20; i++) {\n                    String task = "المهمة رقم " + i;\n                    queue.put(task); // يُحظر إذا كانت القائمة ممتلئة\n                    System.out.println("تمت الإضافة: " + task);\n                    Thread.sleep(100); // محاكاة التوليد\n                }\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        });\n\n        // خيط مستهلك\n        Thread consumer = new Thread(() -> {\n            try {\n                while (true) {\n                    String task = queue.take(); // يُحظر إذا كانت القائمة فارغة\n                    System.out.println("تمت المعالجة: " + task);\n                    Thread.sleep(300); // محاكاة المعالجة\n                }\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        });\n\n        producer.start();\n        consumer.start();\n    }\n}\n
\n\n

يوضح هذا الكود النمط الأساسي: يضيف المنتج المهام عبر put()، ويأخذها المستهلك عبر take(). كلا الطريقتين تُحظران عند الحاجة، مما يضمن التزامن الطبيعي.

\n\n

ThreadPoolExecutor: قائمة مهام احترافية

\n\n

في الممارسة العملية، نادرًا ما يُستخد

المدونات

توصيات الكتب