it-swarm.dev

حجم التجمع الأساسي مقابل الحد الأقصى لحجم التجمع في ThreadPoolExecutor

ما هو الفرق بين حجم التجمع الأساسي والحد الأقصى لحجم التجمع عندما نتحدث من ناحية ThreadPoolExecutor؟ هل يمكن تفسير ذلك بمساعدة مثال؟

64
user2568266

من هذا بلوق وظيفة :

خذ هذا المثال. حجم تجمع مؤشر الترابط البدء هو 1 ، وحجم التجمع الأساسي هو 5 ، والحد الأقصى لحجم التجمع هو 10 وقائمة الانتظار 100.

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

91
user2568266

إذا تشغيل مؤشرات الترابط> corePoolSize & <maxPoolSize ، ثم قم بإنشاء مؤشر ترابط جديد إذا كانت قائمة انتظار المهام الكاملة ممتلئة ووصلت قائمة جديدة.

مستند doc: (إذا كان هناك أكثر من corePoolSize ولكن أقل من maxPoolSize مؤشرات الترابط قيد التشغيل ، سيتم إنشاء سلسلة رسائل جديدة فقط إذا كانت قائمة الانتظار ممتلئة.)

الآن ، خذ مثال بسيط ،

ThreadPoolExecutor executorPool = new ThreadPoolExecutor(5, 10, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(50));

هنا ، 5 هو corePoolSize - يعني أن Jvm سينشئ سلسلة جديدة لمهمة جديدة لأول 5 مهام. وستتم إضافة مهام أخرى إلى قائمة الانتظار حتى تصبح قائمة الانتظار كاملة (50 مهمة).

10 هو maxPoolSize - يمكن لـ JVM إنشاء 10 مؤشرات ترابط كحد أقصى. يعني إذا كان هناك بالفعل 5 مهام/سلسلة عمليات قيد التشغيل وكانت قائمة الانتظار ممتلئة بـ 50 مهمة معلقة وإذا كان هناك طلب/مهمة جديدة أخرى تصل إلى قائمة الانتظار ، فستنشئ JVM سلسلة رسائل جديدة حتى 10 (إجمالي سلاسل الرسائل = 5 + جديدة سابقة) .

ArrayBlockingQueue (50) الجديد = هو حجم قائمة انتظار إجمالي - يمكن أن يصطف في قائمة الانتظار 50 مهمة.

بمجرد تشغيل كافة مؤشرات الترابط العشرة وإذا كانت مهمة جديدة تصل ، فسيتم رفض هذه المهمة الجديدة.

قواعد لإنشاء مؤشرات ترابط داخليًا بواسطة Sun:

  1. إذا كان عدد مؤشرات الترابط أقل من corePoolSize ، فقم بإنشاء مؤشر ترابط جديد لتشغيل مهمة جديدة.

  2. إذا كان عدد مؤشرات الترابط يساوي (أو أكبر من) corePoolSize ، ضع المهمة في قائمة الانتظار.

  3. إذا كانت قائمة الانتظار ممتلئة ، وكان عدد مؤشرات الترابط أقل من maxPoolSize ، فقم بإنشاء سلسلة رسائل جديدة لتشغيل المهام فيها.

  4. إذا كانت قائمة الانتظار ممتلئة ، وكان عدد مؤشرات الترابط أكبر من أو يساوي maxPoolSize ، رفض المهمة.

أمل ، هذا هو HelpFul .. والرجاء تصحيح لي إذا كنت مخطئا ...

21
Darshan Dalwadi

من الوثيقة :

عند إرسال مهمة جديدة في تنفيذ الأسلوب (Java.lang.Runnable) ، وتشغيل أقل من مؤشرات الترابط الأساسيةPoolSize ، يتم إنشاء مؤشر ترابط جديد لمعالجة الطلب ، حتى لو كانت مؤشرات ترابط العامل الأخرى في وضع الخمول. إذا كان هناك أكثر من corePoolSize ولكن أقل من الحد الأقصى من مؤشرات الترابطPoolPool قيد التشغيل ، سيتم إنشاء مؤشر ترابط جديد فقط إذا كانت قائمة الانتظار ممتلئة.

علاوة على ذلك:

من خلال تحديد corePoolSize والحد الأقصىPoolSize نفسه ، يمكنك إنشاء تجمع مؤشر ترابط ثابت الحجم. عن طريق تعيين الحد الأقصىPoolSize إلى قيمة غير محدودة أساساً مثل Integer.MAX_VALUE ، تسمح للمجمع باستيعاب عدد اعتباطي من المهام المتزامنة. غالبًا ما يتم تعيين أحجام التجمعات الأساسية والحد الأقصى فقط عند الإنشاء ، ولكن يمكن أيضًا تغييرها ديناميكيًا باستخدام setCorePoolSize (int) و setMaximumPoolSize (int).

17
Brian Agnew

إذا قررت إنشاء ThreadPoolExecutor يدويًا بدلاً من استخدام فئة المصنع Executors ، فستحتاج إلى إنشاء واحدة وتكوينها باستخدام أحد مُنشئيها. المنشئ الأكثر شمولاً لهذا الفصل هو:

public ThreadPoolExecutor(
    int corePoolSize,
    int maxPoolSize,
    long keepAlive,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    RejectedExecutionHandler handler
);

كما ترون ، يمكنك تكوين:

  • حجم التجمع الأساسي (حجم تجمع مؤشر الترابط سيحاول التمسك به).
  • الحد الأقصى لحجم التجمع.
  • وقت البقاء على قيد الحياة ، وهو الوقت الذي يكون بعده مؤشر ترابط الخمول مؤهلاً للهدم.
  • قائمة انتظار العمل للاحتفاظ بالمهام التي تنتظر التنفيذ.
  • السياسة الواجب تطبيقها عند رفض تقديم المهمة.

الحد من عدد المهام في قائمة الانتظار

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

هذا حل لجزء واحد فقط من المشكلة: أنت تحدّد عدد المهام التي يتم تنفيذها ولكنك لا تحدّ عدد الوظائف التي يمكن إرسالها وتخصيصها للتنفيذ لاحقًا. سيواجه التطبيق نقصًا في الموارد لاحقًا ، ولكنه سيواجهه في النهاية إذا زاد معدل الإرسال عن معدل التنفيذ.

الحل لهذه المشكلة هو: توفير قائمة انتظار حظر للمنفذ لعقد المهام في انتظار. في حالة تعبئة قائمة الانتظار ، سيتم رفض "المهمة" المقدمة. يتم استدعاء RejectedExecutionHandler عند رفض إرسال مهمة ، ولهذا السبب تم نقل الفعل المرفوض في العنصر السابق. يمكنك تنفيذ سياسة الرفض الخاصة بك أو استخدام أحد السياسات المضمنة التي يوفرها الإطار.

سياسات الرفض الافتراضية تجعل المشرف يرمي RejectedExecutionException. ومع ذلك ، تتيح لك السياسات المضمنة الأخرى:

  • تجاهل وظيفة بصمت.
  • تجاهل أقدم وظيفة ومحاولة إعادة إرسال آخر وظيفة.
  • تنفيذ المهمة المرفوضة على مؤشر ترابط المتصل.
5
Prashant Gautam

يمكنك العثور على تعريف المصطلحات corepoolsize و maxpoolsize في javadoc. http://docs.Oracle.com/javase/6/docs/api/Java/util/concurrent/ThreadPoolExecutor.html

يحتوي الرابط أعلاه على إجابة لسؤالك. ومع ذلك ، فقط لتوضيح ذلك. سيبقي التطبيق على إنشاء سلاسل رسائل حتى يصل إلى corePoolSize. أعتقد أن الفكرة هنا هي أن هذه الخيوط الكثيرة يجب أن تكون كافية للتعامل مع تدفق المهام. إذا جاءت مهمة جديدة بعد إنشاء مؤشرات الترابط الأساسيةPoolSize ، فسيتم وضع المهام في قائمة الانتظار. بمجرد امتلاء قائمة الانتظار ، سيبدأ المنفذ في إنشاء سلاسل رسائل جديدة. إنه نوع من التوازن. ما يعنيه بشكل أساسي هو أن تدفق المهام أكثر من سعة المعالجة. لذلك ، سيبدأ Executor في إنشاء سلاسل جديدة مرة أخرى حتى يصل إلى الحد الأقصى لعدد سلاسل الرسائل. مرة أخرى ، سيتم إنشاء سلاسل رسائل جديدة إذا كانت قائمة الانتظار ممتلئة وفقط.

3
Braj Kishore

شرح جيد في هذا بلوق:

توضيح

public class ThreadPoolExecutorExample {

    public static void main (String[] args) {
        createAndRunPoolForQueue(new ArrayBlockingQueue<Runnable>(3), "Bounded");
        createAndRunPoolForQueue(new LinkedBlockingDeque<>(), "Unbounded");
        createAndRunPoolForQueue(new SynchronousQueue<Runnable>(), "Direct hand-off");
    }

    private static void createAndRunPoolForQueue (BlockingQueue<Runnable> queue,
                                                                      String msg) {
        System.out.println("---- " + msg + " queue instance = " +
                                                  queue.getClass()+ " -------------");

        ThreadPoolExecutor e = new ThreadPoolExecutor(2, 5, Long.MAX_VALUE,
                                 TimeUnit.NANOSECONDS, queue);

        for (int i = 0; i < 10; i++) {
            try {
                e.execute(new Task());
            } catch (RejectedExecutionException ex) {
                System.out.println("Task rejected = " + (i + 1));
            }
            printStatus(i + 1, e);
        }

        e.shutdownNow();

        System.out.println("--------------------\n");
    }

    private static void printStatus (int taskSubmitted, ThreadPoolExecutor e) {
        StringBuilder s = new StringBuilder();
        s.append("poolSize = ")
         .append(e.getPoolSize())
         .append(", corePoolSize = ")
         .append(e.getCorePoolSize())
         .append(", queueSize = ")
         .append(e.getQueue()
                  .size())
         .append(", queueRemainingCapacity = ")
         .append(e.getQueue()
                  .remainingCapacity())
         .append(", maximumPoolSize = ")
         .append(e.getMaximumPoolSize())
         .append(", totalTasksSubmitted = ")
         .append(taskSubmitted);

        System.out.println(s.toString());
    }

    private static class Task implements Runnable {

        @Override
        public void run () {
            while (true) {
                try {
                    Thread.sleep(1000000);
                } catch (InterruptedException e) {
                    break;
                }
            }
        }
    }
}

انتاج :

---- Bounded queue instance = class Java.util.concurrent.ArrayBlockingQueue -------------
poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 3, maximumPoolSize = 5, totalTasksSubmitted = 1
poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 3, maximumPoolSize = 5, totalTasksSubmitted = 2
poolSize = 2, corePoolSize = 2, queueSize = 1, queueRemainingCapacity = 2, maximumPoolSize = 5, totalTasksSubmitted = 3
poolSize = 2, corePoolSize = 2, queueSize = 2, queueCapacity = 1, maximumPoolSize = 5, totalTasksSubmitted = 4
poolSize = 2, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 5
poolSize = 3, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 6
poolSize = 4, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 7
poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 8
Task rejected = 9
poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 9
Task rejected = 10
poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 10
--------------------

---- Unbounded queue instance = class Java.util.concurrent.LinkedBlockingDeque -------------
poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 2147483647, maximumPoolSize = 5, totalTasksSubmitted = 1
poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 2147483647, maximumPoolSize = 5, totalTasksSubmitted = 2
poolSize = 2, corePoolSize = 2, queueSize = 1, queueRemainingCapacity = 2147483646, maximumPoolSize = 5, totalTasksSubmitted = 3
poolSize = 2, corePoolSize = 2, queueSize = 2, queueRemainingCapacity = 2147483645, maximumPoolSize = 5, totalTasksSubmitted = 4
poolSize = 2, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 2147483644, maximumPoolSize = 5, totalTasksSubmitted = 5
poolSize = 2, corePoolSize = 2, queueSize = 4, queueRemainingCapacity = 2147483643, maximumPoolSize = 5, totalTasksSubmitted = 6
poolSize = 2, corePoolSize = 2, queueSize = 5, queueRemainingCapacity = 2147483642, maximumPoolSize = 5, totalTasksSubmitted = 7
poolSize = 2, corePoolSize = 2, queueSize = 6, queueRemainingCapacity = 2147483641, maximumPoolSize = 5, totalTasksSubmitted = 8
poolSize = 2, corePoolSize = 2, queueSize = 7, queueRemainingCapacity = 2147483640, maximumPoolSize = 5, totalTasksSubmitted = 9
poolSize = 2, corePoolSize = 2, queueSize = 8, queueRemainingCapacity = 2147483639, maximumPoolSize = 5, totalTasksSubmitted = 10
--------------------

---- Direct hand-off queue instance = class Java.util.concurrent.SynchronousQueue -------------
poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 1
poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 2
poolSize = 3, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 3
poolSize = 4, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 4
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 5
Task rejected = 6
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 6
Task rejected = 7
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 7
Task rejected = 8
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 8
Task rejected = 9
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 9
Task rejected = 10
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 10
--------------------


Process finished with exit code 0
1
rxt66

Java.util.concurrent.ThreadPoolExecutor

  public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }
0
宏杰李