Ukuran kumpulan inti vs ukuran kumpulan maksimum di ThreadPoolExecutor


Jawaban:


130

Dari postingan blog ini :

Ambil contoh ini. Ukuran kumpulan utas awal adalah 1, ukuran kumpulan inti adalah 5, ukuran kumpulan maksimum adalah 10 dan antrian adalah 100.

Saat permintaan masuk, utas akan dibuat hingga 5 dan kemudian tugas akan ditambahkan ke antrian hingga mencapai 100. Saat antrian penuh, utas baru akan dibuat hingga maxPoolSize. Setelah semua utas digunakan dan antrian selesai, tugas akan ditolak. Saat antrian berkurang, begitu pula jumlah utas aktif.


Apakah ini benar? Saya pikir utas baru akan dibuat hingga mencapai maxPoolSize. Kemudian utas baru apa pun akan dimasukkan ke dalam antrean. Harap perbaiki jika saya salah ..
Meluncur

4
Ya, ini benar. Thread hanya akan ditambahkan di luar corePoolSize jika ada tugas dalam antrian. Utas tambahan ini akan "mati" setelah antrian mencapai nol.
Luke

3
Ada sebuah metode yang menarik allowCoreThreadTimeOut(boolean)yang memungkinkan benang inti untuk dibunuh setelah diberikan waktu idle. Menyetel ini ke true dan setelan core threads= max threadsmemungkinkan kumpulan utas berskala antara 0 dan max threads.
Jaroslaw Pawlak

4
Anda baru saja menyalinnya dari sini bigsoft.co.uk/blog/index.php/2009/11/27/…
Kumar Manish

1
Apa yang terjadi dengan tugas yang ditolak?
Lilin

54

JIKA menjalankan utas> corePoolSize & <maxPoolSize , maka buat Thread baru jika antrian tugas Total penuh dan yang baru tiba.

Formulir doc: (Jika ada lebih dari corePoolSize tetapi kurang dari maximumPoolSize utas yang berjalan, utas baru akan dibuat hanya jika antrian penuh.)

Sekarang, ambil contoh sederhana,

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

Di sini, 5 adalah corePoolSize - artinya Jvm akan membuat utas baru untuk tugas baru untuk 5 tugas pertama. dan tugas lainnya akan ditambahkan ke antrian sampai antrian penuh (50 tugas).

10 adalah maxPoolSize - JVM dapat membuat maksimal 10 thread. Berarti jika sudah ada 5 task / thread yang sedang berjalan dan antrian sudah penuh dengan 50 tugas tertunda dan jika satu lagi request / tugas baru sudah masuk antrian maka JVM akan membuat thread baru hingga 10 (total threads = sebelumnya 5 + baru 5) ;

new ArrayBlockingQueue (50) = adalah ukuran antrian total - dapat mengantri 50 tugas di dalamnya.

setelah semua 10 utas berjalan dan jika tugas baru tiba, maka tugas baru itu akan ditolak.

Aturan untuk membuat Thread secara internal oleh SUN:

  1. Jika jumlah utas kurang dari corePoolSize, buat utas baru untuk menjalankan tugas baru.

  2. Jika jumlah utas sama (atau lebih besar dari) corePoolSize, letakkan tugas ke dalam antrian.

  3. Jika antrean penuh, dan jumlah utas kurang dari maxPoolSize, buat utas baru untuk menjalankan tugas.

  4. Jika antrian penuh, dan jumlah utas lebih besar dari atau sama dengan maxPoolSize, tolak tugas.

Harapan, Ini HelpFul .. dan tolong perbaiki saya jika saya salah ...


21

Dari dokumen :

Saat tugas baru dikirimkan dalam metode eksekusi (java.lang.Runnable), dan lebih sedikit dari thread corePoolSize yang berjalan, thread baru akan dibuat untuk menangani permintaan tersebut, bahkan jika thread pekerja lain tidak aktif. Jika ada lebih dari corePoolSize tetapi kurang dari maximumPoolSize threads yang berjalan, thread baru akan dibuat hanya jika antrian penuh.

Selanjutnya:

Dengan menyetel corePoolSize dan maximumPoolSize yang sama, Anda membuat kumpulan utas ukuran tetap. Dengan menyetel maximumPoolSize ke nilai yang pada dasarnya tidak dibatasi seperti Integer.MAX_VALUE, Anda mengizinkan kumpulan untuk mengakomodasi sejumlah tugas serentak yang berubah-ubah. Biasanya, ukuran inti dan kumpulan maksimum disetel hanya pada konstruksi, tetapi mereka juga dapat diubah secara dinamis menggunakan setCorePoolSize (int) dan setMaximumPoolSize (int).


1) Saat tugas baru dikirimkan dalam metode eksekusi (java.lang.Runnable), dan lebih sedikit dari thread corePoolSize yang berjalan, thread baru dibuat untuk menangani permintaan tersebut, bahkan jika thread pekerja lain tidak aktif. Mengapa ada kebutuhan untuk membuat thread baru untuk menangani permintaan jika ada thread yang tidak aktif?
pengguna2568266

1
2) Jika ada lebih dari corePoolSize tetapi kurang dari maximumPoolSize threads yang berjalan, thread baru akan dibuat hanya jika antrian penuh. Saya tidak mengerti perbedaan antara corePoolSize dan maximumPoolSize di sini. Kedua, bagaimana antrian bisa penuh ketika utas kurang dari maximumPoolSize? Antrian hanya bisa penuh jika utas sama dengan maximumPoolSize. Bukan?
pengguna2568266

9

Jika Anda memutuskan untuk membuat ThreadPoolExecutorsecara manual daripada menggunakan Executorskelas pabrik, Anda perlu membuat dan mengonfigurasinya menggunakan salah satu konstruktornya. Konstruktor paling luas dari kelas ini adalah:

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

Seperti yang Anda lihat, Anda dapat mengonfigurasi:

  • Ukuran kolam inti (ukuran kolam benang yang akan coba digunakan).
  • Ukuran kolam maksimum.
  • Waktu simpan, yang merupakan waktu setelah utas menganggur memenuhi syarat untuk dirobohkan.
  • Antrian pekerjaan untuk menahan tugas yang menunggu eksekusi.
  • Kebijakan untuk diterapkan ketika pengiriman tugas ditolak.

Membatasi Jumlah Tugas yang Antri

Membatasi jumlah tugas serentak yang sedang dijalankan, menentukan ukuran kumpulan thread Anda, mewakili manfaat besar bagi aplikasi Anda dan lingkungan eksekusinya dalam hal prediktabilitas dan stabilitas: pembuatan thread tak terbatas pada akhirnya akan menghabiskan sumber daya waktu proses dan aplikasi Anda mungkin mengalami sebagai konsekuensinya , masalah kinerja serius yang bahkan dapat menyebabkan ketidakstabilan aplikasi.

Itu adalah solusi hanya untuk satu bagian dari masalah: Anda membatasi jumlah tugas yang sedang dijalankan tetapi tidak membatasi jumlah pekerjaan yang dapat dikirim dan diantrekan untuk dieksekusi nanti. Aplikasi akan mengalami kekurangan sumber daya nanti, tetapi pada akhirnya akan mengalaminya jika tingkat pengiriman secara konsisten melebihi tingkat eksekusi.

Solusi untuk masalah ini adalah: Menyediakan antrian pemblokiran kepada pelaksana untuk menahan tugas yang menunggu. Jika antrian terisi, tugas yang dikirimkan akan "ditolak". The RejectedExecutionHandlerdipanggil saat pengajuan tugas ditolak, dan bahwa itu mengapa kata kerja ditolak dikutip dalam item sebelumnya. Anda dapat menerapkan kebijakan penolakan Anda sendiri atau menggunakan salah satu kebijakan bawaan yang disediakan oleh framework.

Kebijakan penolakan default membuat pelaksana melempar RejectedExecutionException. Namun, kebijakan bawaan lainnya memungkinkan Anda:

  • Buang pekerjaan secara diam-diam.
  • Buang pekerjaan terlama dan coba kirim ulang yang terakhir.
  • Jalankan tugas yang ditolak di utas pemanggil.

5

Sumber

Aturan ukuran kumpulan ThreadPoolExecutor

Aturan untuk ukuran ThreadPoolExecutor'skolam umumnya salah dipahami, karena tidak berfungsi sebagaimana yang Anda pikirkan atau cara yang Anda inginkan.

Ambil contoh ini. Ukuran kumpulan utas awal adalah 1, ukuran kumpulan inti adalah 5, ukuran kumpulan maksimum adalah 10 dan antrian adalah 100.

Cara Sun: karena permintaan masuk utas akan dibuat hingga 5, maka tugas akan ditambahkan ke antrian sampai mencapai 100. Ketika antrian penuh, utas baru akan dibuat hingga maxPoolSize. Setelah semua utas digunakan dan antrian selesai, tugas akan ditolak. Saat antrian berkurang, begitu pula jumlah utas aktif.

Cara yang diantisipasi pengguna: karena permintaan yang masuk dalam utas akan dibuat hingga 10, kemudian tugas akan ditambahkan ke antrean hingga mencapai 100 di mana mereka ditolak. Jumlah utas akan berganti nama maksimal sampai antrian kosong. Ketika antrian kosong, utas akan mati sampai corePoolSizetersisa.

Perbedaannya adalah bahwa pengguna ingin mulai meningkatkan ukuran kolam lebih awal dan menginginkan antrian yang lebih kecil, sedangkan metode Sun ingin menjaga ukuran kolam tetap kecil dan hanya meningkatkannya setelah beban menjadi banyak.

Berikut adalah aturan Sun untuk pembuatan utas dalam istilah sederhana:

  1. Jika jumlah utas kurang dari corePoolSize, buat utas baru untuk menjalankan tugas baru.
  2. Jika jumlah utas sama (atau lebih besar dari) corePoolSize, letakkan tugas ke antrian.
  3. Jika antrian penuh, dan jumlah utas kurang dari maxPoolSize, buat utas baru untuk menjalankan tugas.
  4. Jika antrian penuh, dan jumlah utas lebih besar dari atau sama dengan maxPoolSize, tolak tugas. Panjang dan pendeknya adalah utas baru hanya dibuat ketika antrian terisi, jadi jika Anda menggunakan antrian tak terbatas maka jumlah utas tidak akan melebihi corePoolSize.

Untuk penjelasan yang lebih lengkap, dapatkan dari mulut kuda: ThreadPoolExecutordokumentasi API.

Ada posting forum yang sangat bagus yang memandu Anda tentang cara ThreadPoolExecutorkerjanya dengan contoh kode: http://forums.sun.com/thread.jspa?threadID=5401400&tstart=0

Info lebih lanjut: http://forums.sun.com/thread.jspa?threadID=5224557&tstart=450


3

Anda dapat menemukan definisi dari istilah corepoolsize dan maxpoolsize di javadoc. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html

Tautan di atas memiliki jawaban atas pertanyaan Anda. Namun, hanya untuk memperjelas. Aplikasi akan terus membuat utas hingga mencapai corePoolSize. Saya pikir idenya di sini adalah bahwa banyak utas ini harus cukup untuk menangani masuknya tugas. Jika tugas baru muncul setelah utas corePoolSize dibuat, tugas akan diantrekan. Setelah antrian penuh, pelaksana akan mulai membuat utas baru. Ini semacam keseimbangan. Apa yang dimaksud pada dasarnya adalah bahwa arus masuk tugas lebih dari sekadar kapasitas pemrosesan. Jadi, Pelaksana akan mulai membuat utas baru lagi hingga mencapai jumlah utas Maks. Sekali lagi, utas baru akan dibuat jika dan hanya jika antrian penuh.


3

Penjelasan bagus di blog ini :

Ilustrasi

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;
                }
            }
        }
    }
}

Keluaran:

---- 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

Dari buku esensi konkurensi Java :

CorePoolSize : ThreadPoolExecutor memiliki atribut corePoolSize yang menentukan berapa banyak utas yang akan dimulai hingga utas baru hanya dimulai ketika antrian penuh

MaximumPoolSize : Atribut ini menentukan berapa banyak utas yang dimulai secara maksimal. Anda dapat mengatur ini ke Integer. MAX_VALUE agar tidak memiliki batas atas


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

Memahami perilaku internal ThreadPoolExecutorketika tugas baru dikirimkan membantu saya memahami bagaimana corePoolSizedan maximumPoolSizeberbeda.

Membiarkan:

  • Nmenjadi jumlah utas di pangkalan getPoolSize(),. Utas aktif + utas diam.
  • T menjadi jumlah tugas yang diserahkan ke pelaksana / kumpulan.
  • Cmenjadi ukuran kumpulan inti , getCorePoolSize(). Berapa banyak utas yang dapat dibuat paling banyak per kumpulan untuk tugas masuk sebelum tugas baru masuk ke antrean .
  • Mmenjadi ukuran kolam maksimum , getMaximumPoolSize(). Jumlah maksimum utas yang dapat dialokasikan kumpulan.

Perilaku ThreadPoolExecutordi Java saat tugas baru dikirimkan:

  • Sebab N <= C, utas diam tidak diberi tugas masuk baru, melainkan utas baru dibuat.
  • Untuk N > Cdan jika ada utas yang tidak aktif, maka tugas baru ditetapkan di sana.
  • Untuk N > Cdan jika TIDAK ada utas yang tidak aktif, tugas baru dimasukkan ke dalam antrian. TIDAK ADA BENANG BARU YANG DIBUAT DI SINI.
  • Saat antrian penuh , kami membuat utas baru hingga M. Jika Mtercapai, kami menolak tugas. Yang penting untuk tidak dilakukan di sini adalah kami tidak membuat utas baru hingga antrian penuh!

Sumber:

Contoh

Contoh dengan corePoolSize = 0dan maximumPoolSize = 10dengan kapasitas antrian 50.

Ini akan menghasilkan satu utas aktif di kumpulan hingga antrean memiliki 50 item di dalamnya.

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.

Contoh dengan corePoolSize = 10dan maximumPoolSize = 10dengan kapasitas antrian 50.

Ini akan menghasilkan 10 utas aktif di kumpulan. Ketika antrian memiliki 50 item di dalamnya, tugas akan ditolak.

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`. 
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.