تكرار السؤال: …
الإجابة المختصرة
تدير أحواض الخيوط طابوراً من المهام مع عدد محدد من الخيوط الجاهزة وتمنع انهيار النظام؛ وحجم الحوض للعمليات الحسابية يساوي عدد النوى (N_cpu)، بينما لعمليات الإدخال/الإخراج يساوي N_cpu * (1 + Wait_Time / Compute_Time).
الشرح
إنشاء وتدمير خيط لكل طلب مستخدم يؤدي لانهيار السيرفر بسبب استهلاك الذاكرة. يحتفظ الـ Thread Pool بعدد ثابت من الخيوط العاملة التي تلتقط المهام من BlockingQueue. إذا كانت المهام CPU-bound (تشفير أو ضغط)، فزيادة الخيوط عن عدد النوى يضر الأداء بسبب الـ Context Switching. أما إذا كانت I/O-bound (انتظار قاعدة البيانات أو الشبكة حيث يقضي الخيط 90% من وقته في الانتظار)، فيمكن زيادة الخيوط لـ 10 إلى 50 ضعفاً لتشغيل النوى أثناء انتظار الآخرين.
مثال بالكود
int cores = Runtime.getRuntime().availableProcessors();
// CPU-bound work: about one thread per core
ExecutorService cpuPool = Executors.newFixedThreadPool(cores);
// I/O-bound work: N_cpu * (1 + waitTime / computeTime), measured per task
double waitMs = 90, computeMs = 10;
int ioThreads = (int) (cores * (1 + waitMs / computeMs));
ExecutorService ioPool = Executors.newFixedThreadPool(ioThreads);
// ForkJoinPool uses work-stealing: an idle worker steals tasks from the tail of a busy worker's queue
ForkJoinPool pool = new ForkJoinPool(cores);
long sum = pool.submit(() -> LongStream.rangeClosed(1, 1_000_000).parallel().sum()).get();أخطاء شائعة
- استخدام نفس الـ Thread Pool المشترك للعمليات الحسابية السريعة والعمليات الخارجية البطيئة، مما يؤدي لاختناق المهام السريعة وتعطل الخادم.