ขนาดคอร์พูลเทียบกับขนาดพูลสูงสุดใน ThreadPoolExecutor


108

อะไรคือความแตกต่างระหว่างขนาดของคอร์พูลและขนาดพูลสูงสุดเมื่อเราพูดถึงThreadPoolExecutor?
สามารถอธิบายได้ด้วยความช่วยเหลือของตัวอย่างหรือไม่?


เป็นไปได้ที่จะซ้ำกันของThreadPoolExecutor - Core และขนาดพูลสูงสุด
bummi

คำตอบ:


136

จากบล็อกโพสต์นี้ :

ใช้ตัวอย่างนี้ เธรดพูลเริ่มต้นคือ 1 ขนาดพูลแกนคือ 5 ขนาดพูลสูงสุดคือ 10 และคิวคือ 100

ในฐานะที่ร้องขอมาในหัวข้อจะถูกสร้างขึ้นถึง 5 และงานที่จะถูกเพิ่มลงในคิวจนกว่าจะถึง 100 maxPoolSizeเมื่อคิวเต็มหัวข้อใหม่จะถูกสร้างขึ้นมาเพื่อ เมื่อเธรดทั้งหมดถูกใช้งานและคิวเป็นงานทั้งหมดจะถูกปฏิเสธ เมื่อคิวลดจำนวนเธรดที่ใช้งานอยู่ก็จะลดลง


ถูกต้องหรือไม่ ฉันคิดว่าจะมีการสร้างเธรดใหม่จนกว่าจะถึง maxPoolSize จากนั้นเธรดใหม่จะถูกใส่ไว้ในคิว กรุณาแก้ไขฉันถ้าฉันผิด ..
ร่อน

4
ใช่ถูกต้องแล้ว เธรดจะถูกเพิ่มนอกเหนือจาก corePoolSize เท่านั้นหากมีงานในคิว เธรดเพิ่มเติมเหล่านี้จะ "ตาย" หลังจากคิวถึงศูนย์
ลุค

3
มีวิธีการที่น่าสนใจallowCoreThreadTimeOut(boolean)ซึ่งช่วยให้เธรดหลักถูกฆ่าหลังจากเวลาว่างที่กำหนด การตั้งค่านี้เพื่อความจริงและการตั้งค่าcore threads= max threadsช่วยให้สระว่ายน้ำด้ายขนาดระหว่าง 0 max threadsและ
Jaroslaw Pawlak

4
คุณเพิ่งคัดลอกมาจากที่นี่bigsoft.co.uk/blog/index.php/2009/11/27/…
Kumar Manish

1
จะเกิดอะไรขึ้นกับงานที่ถูกปฏิเสธ
แว็กซ์

54

หากรันเธรด> corePoolSize & <maxPoolSizeจากนั้นสร้างเธรดใหม่หากคิวงานทั้งหมดเต็มและมีอันใหม่มาถึง

แบบฟอร์ม doc: (หากมีเธรด corePoolSizeมากกว่าแต่น้อยกว่าmaximumPoolSizeเธรดที่รันเธรดใหม่จะถูกสร้างขึ้นก็ต่อเมื่อคิวเต็มเท่านั้น)

ยกตัวอย่างง่ายๆ

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 + ใหม่ 5) ;

ใหม่ ArrayBlockingQueue (50) = คือขนาดคิวทั้งหมด - สามารถจัดคิวงานได้ 50 งาน

เมื่อเธรดทั้ง 10 กำลังทำงานและหากมีงานใหม่มาถึงงานใหม่นั้นจะถูกปฏิเสธ

กฎสำหรับการสร้างเธรดภายในโดย SUN:

  1. หากจำนวนเธรดน้อยกว่า corePoolSize ให้สร้าง Thread ใหม่เพื่อรันงานใหม่

  2. ถ้าจำนวนเธรดเท่ากับ (หรือมากกว่า) corePoolSize ให้ใส่งานลงในคิว

  3. หากคิวเต็มและจำนวนเธรดน้อยกว่า maxPoolSize ให้สร้างเธรดใหม่เพื่อรันงาน

  4. หากคิวเต็มและจำนวนเธรดมากกว่าหรือเท่ากับ maxPoolSize ให้ปฏิเสธงาน

หวังว่านี่คือ HelpFul .. และโปรดแก้ไขฉันถ้าฉันผิด ...


21

จากเอกสาร :

เมื่องานใหม่ถูกส่งใน method execute (java.lang.Runnable) และมีเธรด corePoolSize น้อยกว่ากำลังรันเธรดใหม่จะถูกสร้างขึ้นเพื่อจัดการกับคำร้องขอแม้ว่าเธรดผู้ปฏิบัติงานอื่นจะไม่ได้ใช้งานก็ตาม หากมีเธรด corePoolSize มากกว่า แต่น้อยกว่า maximumPoolSize เธรดที่รันเธรดใหม่จะถูกสร้างขึ้นก็ต่อเมื่อคิวเต็ม

นอกจากนี้:

โดยการตั้งค่า corePoolSize และ maximumPoolSize เหมือนกันคุณจะสร้างเธรดพูลขนาดคงที่ โดยการตั้งค่า maximumPoolSize เป็นค่าที่ไม่ถูกผูกมัดเช่น Integer.MAX_VALUE คุณอนุญาตให้พูลรองรับจำนวนงานพร้อมกันโดยพลการ โดยทั่วไปขนาดคอร์และพูลสูงสุดจะถูกกำหนดตามการก่อสร้างเท่านั้น แต่อาจมีการเปลี่ยนแปลงแบบไดนามิกโดยใช้ setCorePoolSize (int) และ setMaximumPoolSize (int)


1) เมื่อส่งงานใหม่ใน method execute (java.lang.Runnable) และมีเธรด corePoolSize น้อยกว่ากำลังรันเธรดใหม่จะถูกสร้างขึ้นเพื่อจัดการกับคำร้องขอแม้ว่าเธรดผู้ปฏิบัติงานอื่นจะไม่ได้ใช้งานก็ตาม เหตุใดจึงจำเป็นต้องสร้างเธรดใหม่เพื่อจัดการคำขอหากมีเธรดที่ไม่ได้ใช้งาน
user2568266

1
2) หากมีเธรด corePoolSize มากกว่า แต่น้อยกว่า maximumPoolSize เธรดที่รันเธรดใหม่จะถูกสร้างขึ้นก็ต่อเมื่อคิวเต็ม ฉันไม่เข้าใจความแตกต่างระหว่าง corePoolSize และ maximumPoolSize ที่นี่ ประการที่สองคิวจะเต็มได้อย่างไรเมื่อเธรดมีค่าน้อยกว่า maximumPoolSize คิวจะเต็มได้ก็ต่อเมื่อเธรดมีค่าเท่ากับ maximumPoolSize ไม่ใช่เหรอ?
user2568266

9

หากคุณตัดสินใจที่จะสร้างThreadPoolExecutorด้วยตนเองแทนที่จะใช้Executorsคลาสโรงงานคุณจะต้องสร้างและกำหนดค่าโดยใช้ตัวสร้างตัวใดตัวหนึ่ง ตัวสร้างที่ครอบคลุมที่สุดของคลาสนี้คือ:

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

อย่างที่คุณเห็นคุณสามารถกำหนดค่า:

  • ขนาดแกนพูล (ขนาดที่พูลเธรดจะพยายามติดด้วย)
  • ขนาดสระว่ายน้ำสูงสุด
  • เวลาที่ยังมีชีวิตอยู่ซึ่งเป็นช่วงเวลาที่เธรดที่ไม่ได้ใช้งานมีสิทธิ์ถูกฉีกขาด
  • คิวงานเพื่อเก็บงานที่รอการดำเนินการ
  • นโยบายที่จะใช้เมื่อการส่งงานถูกปฏิเสธ

การ จำกัด จำนวนงานในคิว

การ จำกัด จำนวนงานที่ดำเนินการพร้อมกันที่กำลังดำเนินการปรับขนาดเธรดพูลของคุณแสดงให้เห็นถึงประโยชน์อย่างมากสำหรับแอปพลิเคชันของคุณและสภาพแวดล้อมการดำเนินการในแง่ของความสามารถในการคาดเดาและความเสถียร: การสร้างเธรดที่ไม่มีขอบเขตจะทำให้ทรัพยากรรันไทม์หมดลงในที่สุดและแอปพลิเคชันของคุณอาจประสบผล ปัญหาด้านประสิทธิภาพที่ร้ายแรงซึ่งอาจนำไปสู่ความไม่แน่นอนของแอปพลิเคชัน

นั่นเป็นวิธีแก้ปัญหาเพียงส่วนเดียว: คุณกำหนดจำนวนงานที่กำลังดำเนินการ แต่ไม่ได้กำหนดจำนวนงานที่สามารถส่งและจัดคิวเพื่อดำเนินการในภายหลังได้ แอปพลิเคชันจะประสบปัญหาการขาดแคลนทรัพยากรในภายหลัง แต่จะพบได้ในที่สุดหากอัตราการส่งข้อมูลสูงกว่าอัตราการดำเนินการอย่างต่อเนื่อง

วิธีแก้ปัญหานี้คือ: จัดเตรียมคิวการบล็อกให้กับผู้ดำเนินการเพื่อเก็บงานที่รออยู่ ในกรณีที่คิวเต็มงานที่ส่งจะถูก "ปฏิเสธ" RejectedExecutionHandlerจะเรียกเมื่อส่งงานถูกปฏิเสธและว่าทำไมคำกริยาปฏิเสธอ้างในรายการก่อนหน้า คุณสามารถใช้นโยบายการปฏิเสธของคุณเองหรือใช้นโยบายในตัวที่มีให้โดยกรอบงาน

นโยบายการปฏิเสธเริ่มต้นมีผู้ปฏิบัติการโยนไฟล์RejectedExecutionException. อย่างไรก็ตามนโยบายในตัวอื่น ๆ ช่วยให้คุณ:

  • ทิ้งงานอย่างเงียบ ๆ
  • ทิ้งงานที่เก่าที่สุดและพยายามส่งงานสุดท้ายอีกครั้ง
  • ดำเนินงานที่ถูกปฏิเสธบนเธรดของผู้โทร

7

ที่มา

กฎของขนาดพูล ThreadPoolExecutor

โดยทั่วไปกฎสำหรับขนาดของThreadPoolExecutor'sพูลนั้นมักจะเข้าใจผิดเพราะมันไม่ได้ผลในแบบที่คุณคิดว่าควรจะเป็นหรือในแบบที่คุณต้องการ

ใช้ตัวอย่างนี้ เธรดพูลเริ่มต้นคือ 1 ขนาดพูลแกนคือ 5 ขนาดพูลสูงสุดคือ 10 และคิวคือ 100

ทางดวงอาทิตย์: การร้องขอมาในหัวข้อจะถูกสร้างขึ้นถึง 5 งานแล้วจะถูกเพิ่มลงในคิวจนกว่าจะถึง 100 maxPoolSizeเมื่อคิวเต็มหัวข้อใหม่จะถูกสร้างขึ้นมาเพื่อ เมื่อเธรดทั้งหมดถูกใช้งานและคิวเป็นงานทั้งหมดจะถูกปฏิเสธ เนื่องจากคิวจะลดจำนวนเธรดที่ใช้งานอยู่

วิธีที่ผู้ใช้คาดหวัง: เนื่องจากคำขอเข้ามาในเธรดจะถูกสร้างขึ้นสูงสุด 10 รายการจากนั้นงานจะถูกเพิ่มลงในคิวจนกว่าจะถึง 100 ณ จุดที่พวกเขาถูกปฏิเสธ จำนวนเธรดจะเปลี่ยนชื่อสูงสุดจนกว่าคิวจะว่างเปล่า เมื่อคิวว่างเธรดจะตายจนกว่าจะcorePoolSizeเหลือ

ความแตกต่างคือผู้ใช้ต้องการเริ่มเพิ่มขนาดพูลก่อนหน้านี้และต้องการให้คิวมีขนาดเล็กลงโดยที่วิธีการของ Sun ต้องการให้ขนาดพูลมีขนาดเล็กและเพิ่มขึ้นก็ต่อเมื่อโหลดมากขึ้นเท่านั้น

นี่คือกฎของ Sun สำหรับการสร้างเธรดในแง่ง่ายๆ:

  1. หากจำนวนเธรดน้อยกว่าให้corePoolSizeสร้างเธรดใหม่เพื่อรันงานใหม่
  2. ถ้าจำนวนเธรดเท่ากัน (หรือมากกว่า) ให้corePoolSizeใส่งานลงในคิว
  3. หากคิวเต็มและจำนวนเธรดน้อยกว่าให้maxPoolSizeสร้างเธรดใหม่เพื่อรันงาน
  4. หากคิวเต็มและจำนวนเธรดมากกว่าหรือเท่ากับให้maxPoolSizeปฏิเสธงาน corePoolSizeยาวและระยะสั้นของมันคือหัวข้อใหม่จะถูกสร้างขึ้นเฉพาะเมื่อคิวเติมขึ้นดังนั้นหากคุณกำลังใช้คิวมากมายแล้วจำนวนกระทู้จะไม่เกิน

หากต้องการคำอธิบายที่สมบูรณ์ยิ่งขึ้นโปรดอ่านจากปากม้า: ThreadPoolExecutorเอกสาร API

มีโพสต์ในฟอรัมที่ดีมากซึ่งพูดถึงวิธีการThreadPoolExecutorทำงานกับตัวอย่างโค้ด: http://forums.sun.com/thread.jspa?threadID=5401400&tstart=0

ข้อมูลเพิ่มเติม: http://forums.sun.com/thread.jspa?threadID=5224557&tstart=450


ขอบคุณ. ฉันชอบคำตอบของคุณมาก กระจายความสว่างในการใช้งานพื้นฐานและตอบคำถามที่ควรถามและตอบเพื่อให้เข้าใจพฤติกรรม corePoolSize / maxPoolSize ของเธรดพูลนี้อย่างแท้จริง
Pavel

3

คุณสามารถค้นหาคำจำกัดความของคำว่า corepoolsize และ maxpoolsize ได้ใน javadoc http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html

ลิงก์ด้านบนมีคำตอบสำหรับคำถามของคุณ อย่างไรก็ตามเพียงเพื่อให้ชัดเจน แอปพลิเคชันจะสร้างเธรดต่อไปจนกว่าจะถึง corePoolSize ฉันคิดว่าแนวคิดในที่นี้คือเธรดจำนวนมากเหล่านี้ควรเพียงพอที่จะรองรับการไหลเข้าของงาน หากงานใหม่เกิดขึ้นหลังจากสร้างเธรด corePoolSize งานจะถูกจัดคิว เมื่อคิวเต็มแล้วตัวดำเนินการจะเริ่มสร้างเธรดใหม่ เป็นการสร้างสมดุล ความหมายโดยพื้นฐานคือการไหลเข้าของงานมากกว่าความสามารถในการประมวลผล ดังนั้นผู้ดำเนินการจะเริ่มสร้างเธรดใหม่อีกครั้งจนกว่าจะถึงจำนวนเธรดสูงสุด อีกครั้งเธรดใหม่จะถูกสร้างขึ้นในกรณีที่คิวเต็มเท่านั้น


3

คำอธิบายที่ดีในบล็อกนี้ :

ภาพประกอบ

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

จากหนังสือJava concurency Essentials :

CorePoolSize : ThreadPoolExecutor มีแอตทริบิวต์ corePoolSize ที่กำหนดจำนวนเธรดที่จะเริ่มทำงานจนกว่าเธรดใหม่จะเริ่มต้นเมื่อคิวเต็มเท่านั้น

MaximumPoolSize : แอตทริบิวต์นี้กำหนดจำนวนเธรดที่เริ่มต้นที่ค่าสูงสุด คุณสามารถตั้งค่านี้เป็นจำนวนเต็ม MAX_VALUE เพื่อที่จะไม่มีขอบเขตบน


0

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

การทำความเข้าใจพฤติกรรมภายในของThreadPoolExecutorเวลาที่ส่งงานใหม่ช่วยให้ฉันเข้าใจว่าอย่างไรcorePoolSizeและmaximumPoolSizeแตกต่างกันอย่างไร

ปล่อย:

  • Nเป็นจำนวนเธรดในพูล, getPoolSize(). เธรดที่ใช้งานอยู่ + เธรดที่ไม่ได้ใช้งาน
  • T เป็นจำนวนงานที่ส่งไปยังผู้ดำเนินการ / พูล
  • CgetCorePoolSize()มีขนาดสระว่ายน้ำหลัก วิธีการหลายหัวข้อที่มากที่สุดสามารถถูกสร้างขึ้นต่อสระว่ายน้ำสำหรับงานที่เข้ามาก่อนงานใหม่ไปที่คิว
  • MgetMaximumPoolSize()สระว่ายน้ำมีขนาดสูงสุด จำนวนเธรดสูงสุดที่พูลสามารถจัดสรรได้

ลักษณะการทำงานของThreadPoolExecutorJava เมื่อส่งงานใหม่:

  • สำหรับN <= Cเธรดที่ไม่ได้ใช้งานจะไม่ได้รับมอบหมายงานขาเข้าใหม่ แต่จะสร้างเธรดใหม่แทน
  • สำหรับN > Cและถ้ามีเธรดที่ไม่ได้ใช้งานงานใหม่จะถูกกำหนดที่นั่น
  • สำหรับN > Cและถ้าไม่มีเธรดที่ไม่ได้ใช้งานงานใหม่จะถูกใส่ลงในคิว ไม่มีการสร้างเธรดใหม่ที่นี่
  • เมื่อคิวเต็มMเราจะสร้างหัวข้อใหม่ได้ถึง หากMถึงแล้วเราปฏิเสธงาน สิ่งสำคัญที่ห้ามพลาดคือห้ามสร้างเธรดใหม่จนกว่าคิวจะเต็ม!

แหล่งที่มา:

ตัวอย่าง

ตัวอย่างที่มีcorePoolSize = 0และmaximumPoolSize = 10ความจุคิวเป็น50.

ซึ่งจะส่งผลให้มีเธรดเดียวที่ใช้งานอยู่ในพูลจนกว่าคิวจะมี 50 รายการในนั้น

executor.execute(task #1):

before task #1 submitted to executor: java.util.concurrent.ThreadPoolExecutor@c52dafe[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]

after task #1 submitted to executor: java.util.concurrent.ThreadPoolExecutor@c52dafe[Running, pool size = 1, active threads = 1, queued tasks = 1, completed tasks = 0]

[task #1 immediately queued and kicked in b/c the very first thread is created when `workerCountOf(recheck) == 0`]

execute(task #2):

before task #2 submitted to executor: java.util.concurrent.ThreadPoolExecutor@c52dafe[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]

after task #2 submitted to executor: java.util.concurrent.ThreadPoolExecutor@c52dafe[Running, pool size = 1, active threads = 1, queued tasks = 1, completed tasks = 0]

[task #2 not starting before #1 is done]

... executed a few tasks...

execute(task #19)

before task #19 submitted to executor: java.util.concurrent.ThreadPoolExecutor@735afe38[Running, pool size = 1, active threads = 1, queued tasks = 17, completed tasks = 0]

after task #19 submitted to executor: java.util.concurrent.ThreadPoolExecutor@735afe38[Running, pool size = 1, active threads = 1, queued tasks = 18, completed tasks = 0]

...

execute(task #51)

before task submitted to executor: java.util.concurrent.ThreadPoolExecutor@735afe38[Running, pool size = 1, active threads = 1, queued tasks = 50, completed tasks = 0]

after task submitted to executor: java.util.concurrent.ThreadPoolExecutor@735afe38[Running, pool size = 2, active threads = 2, queued tasks = 50, completed tasks = 0]

Queue is full.
A new thread was created as the queue was full.

ตัวอย่างที่มีcorePoolSize = 10และmaximumPoolSize = 10ความจุคิวเป็น50.

ซึ่งจะส่งผลให้มีเธรดที่ใช้งาน 10 เธรดในพูล เมื่อคิวมี 50 รายการในนั้นงานจะถูกปฏิเสธ

execute(task #1)

before task #1 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]

after task #1 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]

execute(task #2)

before task #2 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]

after task #2 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]

execute(task #3)

before task #3 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]

after task #3 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]

... executed a few tasks...

execute(task #11)

before task #11 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 10, active threads = 10, queued tasks = 0, completed tasks = 0]

after task #11 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 10, active threads = 10, queued tasks = 1, completed tasks = 0]

... executed a few tasks...

execute(task #51)
before task #51 submitted to executor: java.util.concurrent.ThreadPoolExecutor@32d9e072[Running, pool size = 10, active threads = 10, queued tasks = 50, completed tasks = 0]

Task was rejected as we have reached `maximumPoolSize`. 

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.