قوائم المهام في Java: تحويل الفوضى إلى نظام

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

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

ابدأ الدورة

عندما يبدأ الكود الخاص بك في التلعثم: مقدمة إلى قوائم المهام والمهام الخلفية في Java

\n\n

تخيل الموقف: تقوم بتشغيل خادم ويب بلغة Java. يأتي طلب من مستخدم - تحتاج إلى إرسال بريد إلكتروني، وإنشاء تقرير PDF، وتحديث الإحصائيات. إذا قمت بتنفيذ كل شيء بشكل متزامن، سينتظر المستخدم 30 ثانية. سيبرد قهوته، وسيذهب إلى المنافسين. مألوف؟

\n\n

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

\n\n

اليوم سنشرح كيفية تنفيذ قوائم المهام في Java - من أبسط إصدار أحادي الخيط إلى الحلول الصناعية مع RabbitMQ و Kafka. ستتعلم كيف تتوقف عن إطفاء الحرائق وتبدأ في تصميم أنظمة موثوقة.

\n\n

لماذا نحتاج إلى قوائم المهام؟ ثلاثة أسباب ستفاجئك

\n\n
    \n
  1. عدم التزامن - المستخدم لا ينتظر. سرعة استجابة الخادم تنخفض من 30 ثانية إلى 5 ملي ثانية.
  2. \n
  3. موازنة التحميل - الطلبات الذروة لا تعطل الخادم. يتم تخزين المهام في قائمة الانتظار ومعالجتها مع تحرر الموارد.
  4. \n
  5. تحمل الأخطاء - إذا تعطل عامل واحد، تبقى المهمة في قائمة الانتظار. عامل آخر سيلتقطها. لا يتم فقدان البيانات.
  6. \n
\n\n

في Java، توجد أدوات مدمجة لهذا (ExecutorService، BlockingQueue) ووسطاء خارجيون (RabbitMQ، Kafka). يعتمد الاختيار على النطاق. لنبدأ من الصغير.

\n\n

قائمة مهام بسيطة في Java: ExecutorService و BlockingQueue

\n\n

إذا كنت لا تحتاج إلى نظام موزع، وتريد فقط نقل العمل الثقيل إلى الخلفية - استخدم ThreadPoolExecutor. هذا هو مجمع خيوط مدمج يأخذ المهام من قائمة الانتظار.

\n\n

مثال: مجمع خيوط لمعالجة الطلبات

\n\n
import java.util.concurrent.*;\n\npublic class OrderProcessor {\n    private final ExecutorService executor;\n\n    public OrderProcessor(int threadCount) {\n        // إنشاء مجمع بعدد ثابت من الخيوط\n        this.executor = Executors.newFixedThreadPool(threadCount);\n    }\n\n    public void processOrder(Order order) {\n        executor.submit(() -> {\n            // عمل ثقيل: إنشاء إيصال، إرسال بريد إلكتروني، تحديث المخزون\n            System.out.println("معالجة الطلب: " + order.getId());\n            try {\n                Thread.sleep(2000); // محاكاة العمل\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n            System.out.println("الطلب " + order.getId() + " تمت معالجته");\n        });\n    }\n\n    public void shutdown() {\n        executor.shutdown();\n    }\n\n    public static void main(String[] args) {\n        OrderProcessor processor = new OrderProcessor(4);\n        for (int i = 0; i < 10; i++) {\n            processor.processOrder(new Order(i));\n        }\n        processor.shutdown();\n    }\n}\n\nclass Order {\n    private final int id;\n    public Order(int id) { this.id = id; }\n    public int getId() { return id; }\n}
\n\n

ماذا يحدث هنا؟ أنشأنا مجمعًا من 4 خيوط. سيتم معالجة 10 طلبات بمعدل 4 طلبات بالتوازي. تتم إدارة قائمة مهام Java داخليًا بواسطة ThreadPoolExecutor - وهي LinkedBlockingQueue افتراضيًا. عندما تكون جميع الخيوط مشغولة، تنتظر المهام دورها في قائمة الانتظار.

\n\n

إعداد متقدم: الأولويات وتحمل الأخطاء

\n\n

ماذا لو كانت المهام عاجلة؟ استخدم PriorityBlockingQueue:

\n\n
BlockingQueue<Runnable> priorityQueue = new PriorityBlockingQueue<>(\n    10,\n    Comparator.comparingInt(task -> ((PriorityTask) task).getPriority())\n);\n\nThreadPoolExecutor executor = new ThreadPoolExecutor(\n    2, 4, 60, TimeUnit.SECONDS, priorityQueue\n);
\n\n

الآن المهام ذات الأولوية العالية

المدونات

توصيات الكتب