التزامن وتعدد الخيوط في Java: تقنيات متقدمة

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

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

ابدأ الدورة

التزامن وتعدد الخيوط في Java: مستوى متقدم

\n\n

تعدد الخيوط في Java هو واحد من أقوى المواضيع وأكثرها تعقيدًا في نفس الوقت. على المستوى الأساسي، نستخدم synchronized و Thread، ولكن لبناء أنظمة فعالة وقابلة للتوسع، نحتاج إلى فهم أعمق. في هذه المقالة، سنستعرض الآليات المتقدمة للتزامن: تجمعات الخيوط، ForkJoinPool، البرمجة غير المتزامنة مع CompletableFuture، الضبط الدقيق للأقفال، والعمل مع الذاكرة. المادة موجهة للمطورين الذين لديهم بالفعل معرفة أساسية بتعدد الخيوط.

\n\n

1. العمل المتقدم مع تجمعات الخيوط: ExecutorService والضبط

\n\n

استخدام ExecutorService هو المعيار في التطوير الصناعي. ومع ذلك، فإن Executors.newFixedThreadPool(10) القياسي ليس مناسبًا دائمًا. دعنا نستعرض الضبط الدقيق لـ ThreadPoolExecutor.

\n\n
import java.util.concurrent.*;\n\npublic class CustomThreadPool {\n    public static void main(String[] args) {\n        int corePoolSize = 4;\n        int maxPoolSize = 8;\n        long keepAliveTime = 30;\n        TimeUnit unit = TimeUnit.SECONDS;\n        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(100);\n\n        ThreadPoolExecutor executor = new ThreadPoolExecutor(\n                corePoolSize,\n                maxPoolSize,\n                keepAliveTime,\n                unit,\n                workQueue,\n                new ThreadPoolExecutor.CallerRunsPolicy() // سياسة التشبع\n        );\n\n        // مراقبة حالة التجمع\n        executor.submit(() -> {\n            System.out.println("الخيوط النشطة: " + executor.getActiveCount());\n            System.out.println("المهام المكتملة: " + executor.getCompletedTaskCount());\n        });\n\n        executor.shutdown();\n    }\n}
\n\n

المعلمات الرئيسية:

\n
    \n
  • corePoolSize — الحد الأدنى لعدد الخيوط التي تبقى حتى بدون مهام.
  • \n
  • maxPoolSize — الحد الأقصى لعدد الخيوط.
  • \n
  • keepAliveTime — وقت بقاء الخيوط الزائدة عن الحاجة.
  • \n
  • workQueue — قائمة انتظار المهام. ArrayBlockingQueue بحجم محدود يمنع تجاوز الذاكرة.
  • \n
  • سياسة التشبع — ما يجب فعله إذا كانت قائمة الانتظار ممتلئة وجميع الخيوط مشغولة. CallerRunsPolicy يبطئ الخيط المستدعي.
  • \n
\n\n

لمهام الإدخال/الإخراج الطويلة، من الأفضل زيادة corePoolSize، بينما للمهام المكثفة على المعالج (CPU-bound)، يُفضل الاعتماد على Runtime.getRuntime().availableProcessors().

\n\n

2. ForkJoinPool والمهام التكرارية

\n\n

ForkJoinPool هو تجمع متخصص للمهام التي يمكن تقسيمها إلى مهام فرعية (فرق تسد). يستخدم بشكل فعال سرقة العمل (work stealing).

\n\n

مثال: حساب مجموع عناصر مصفوفة بشكل تكراري.

\n\n
import java.util.concurrent.RecursiveTask;\nimport java.util.concurrent.ForkJoinPool;\n\npublic class SumTask extends RecursiveTask<Long> {\n    private static final int THRESHOLD = 1000;\n    private final int[] array;\n    private final int start;\n    private final int end;\n\n    public SumTask(int[] array, int start, int end) {\n        this.array = array;\n        this.start = start;\n        this.end = end;\n    }\n\n    @Override\n    protected Long compute() {\n        if (end - start <= THRESHOLD) {\n            long sum = 0;\n            for (int i = start; i < end; i++) {\n                sum += array[i];\n            }\n            return sum;\n        }\n        int mid = (start + end) / 2;\n        SumTask leftTask = new SumTask(array, start, mid);\n        SumTask rightTask = new SumTask(array, mid, end);\n\n        leftTask.fork(); // تشغيل غير متزامن\n        long rightResult = rightTask.compute(); // حساب                

المدونات

توصيات الكتب