Metode FixedThreadPool saka kelas Executors nggawe executorService kanthi jumlah benang sing tetep. Boten kados metode newSingleThreadExecutor , kita nemtokake jumlah utas sing dikarepake ing blumbang. Ing hood, kode ing ngisor iki diarani:

new ThreadPoolExecutor(nThreads, nThreads,
                                      	0L, TimeUnit.MILLISECONDS,
                                      	new LinkedBlockingQueue());

Parameter corePoolSize (jumlah utas sing bakal siap (diwiwiti) nalika layanan eksekutor diwiwiti) lan maksimumPoolSize (jumlah maksimum utas sing bisa digawe layanan eksekutor ) nampa nilai sing padha - jumlah utas sing dikirim menyang newFixedThreadPool(nThreads ) . Lan kita bisa ngliwati implementasine ThreadFactory kanthi cara sing padha.

Ya, ayo goleki kenapa kita butuh ExecutorService kaya ngono .

Mangkene logika saka ExecutorService kanthi nomer tetep (n) benang:

  • Maksimal n utas bakal aktif kanggo ngolah tugas.
  • Yen luwih saka n tugas diajukake, padha bakal dianakaké ing antrian nganti Utas dadi free.
  • Yen salah siji utas gagal lan mungkasi, utas anyar bakal digawe kanggo ngganti.
  • Utas apa wae ing blumbang aktif nganti blumbang ditutup.

Minangka conto, mbayangno ngenteni liwat keamanan ing bandara. Saben uwong ngadeg ing siji baris nganti sadurunge mriksa keamanan, penumpang disebarake ing kabeh pos pemeriksaan. Yen ana wektu tundha ing salah sawijining checkpoint, antrian bakal diproses mung sing nomer loro nganti sing pertama gratis. Lan yen siji checkpoint ditutup kabeh, banjur checkpoint liyane bakal dibukak kanggo ngganti, lan penumpang bakal terus diproses liwat loro checkpoints.

Kita bakal langsung nyathet yen sanajan kahanan sing cocog - benang sing dijanjekake bisa digunakake kanthi stabil, lan benang sing diakhiri karo kesalahan mesthi diganti (soko sumber daya winates ora bisa ditindakake ing bandara nyata) - sistem isih duwe sawetara fitur karu, amarga ing kahanan ora bakal ana liyane Utas, malah yen antrian mundak akeh luwih cepet saka Utas bisa proses tugas.

Aku saranake entuk pangerten praktis babagan cara ExecutorService bisa digunakake kanthi jumlah benang sing tetep. Ayo nggawe kelas sing ngetrapake Runnable . Obyek kelas iki makili tugas kita kanggo ExecutorService .

public class Task implements Runnable {
    int taskNumber;

    public Task(int taskNumber) {
        this.taskNumber = taskNumber;
    }

    @Override
    public void run() {
try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Processed user request #" + taskNumber + " on thread " + Thread.currentThread().getName());
    }
}

Ing cara roto () , kita mblokir Utas kanggo 2 detik, simulating sawetara workload, banjur nampilake nomer tugas saiki lan jeneng thread nglakokaké tugas.

ExecutorService executorService = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 30; i++) {
            executorService.execute(new Task(i));
        }

        executorService.shutdown();

Kanggo miwiti, ing cara utama , kita nggawe ExecutorService lan ngirim 30 tugas kanggo eksekusi.

Panjaluk pangguna sing diproses #1 ing thread pool-1-thread-2
Panjaluk pangguna sing diproses #0 ing thread pool-1-thread-1
Panjaluk pangguna sing diproses #2 ing thread pool-1-thread-3 Panjaluk
pangguna sing diproses #5 ing pool- Utas 1-utas-3
Panjaluk pangguna sing diproses #3 ing Utas pool-1-Utas-2 Utas
sing diproses Panjaluk pangguna #4 ing Utas pool-1-Utas-1
Panjaluk pangguna sing wis diproses #8 ing Utas pool-1-Utas-1
Pangguna sing diproses request #6 ing pool-1-thread-3 thread
Panjaluk pangguna sing diproses #7 ing pool-1-thread-2 thread
Panjaluk pangguna sing diproses #10 ing pool-1-thread-3 thread
Panyuwunan pangguna sing diproses #9 ing pool-1- thread-1 thread
Panjaluk pangguna sing diproses #11 ing pool-1-thread-2 thread
Panjaluk pangguna sing diproses #12 ing pool-1-thread-3 thread
Panjaluk pangguna sing diproses #14 ing thread pool-1-thread-2
Panjaluk pangguna sing diproses #13 ing pool-1-thread-1 thread
Panyuwunan pangguna sing diproses #15 ing pool-1-thread-3 thread
Panyuwunan pangguna sing diproses #16 ing pool- Utas 1-utas-2
Panjaluk pangguna sing diproses #17 ing Utas pool-1-Utas-1 Utas
sing diproses Panjaluk pangguna #18 ing Utas pool-1-Utas-3
Panjaluk pangguna sing wis diproses #19 ing Utas pool-1-Utas-2
Pangguna sing diproses request #20 ing pool-1-thread-1 thread
Panjaluk pangguna sing diproses #21 ing pool-1-thread-3 thread
Panyuwunan pangguna sing diproses #22 ing pool-1-thread-2 thread
Panyuwunan pangguna sing diproses #23 ing pool-1- thread-1 thread
Panjaluk pangguna sing diproses #25 ing pool-1-thread-2 thread
Panjaluk pangguna sing diproses #24 ing pool-1-thread-3 thread
Panjaluk pangguna sing diproses #26 ing thread pool-1-thread-1
Panjaluk pangguna sing diproses #27 ing pool-1-thread-2 thread
Panyuwunan pangguna sing diproses #28 ing pool-1-thread-3 thread
Panyuwunan pangguna sing diproses #29 ing pool- 1-thread-1 thread

Output console nuduhake kita carane tugas dileksanakake ing Utas beda sawise padha dirilis dening tugas sadurungé.

Saiki kita bakal nambah jumlah tugas dadi 100, lan sawise ngirim 100 tugas, kita bakal nelpon metode awaitTermination(11, SECONDS) . We pass nomer lan unit wektu minangka bantahan. Cara iki bakal mblokir utas utama sajrone 11 detik. Banjur kita bakal nelpon shutdownNow () kanggo meksa ExecutorService mati tanpa ngenteni kabeh tugas rampung.

ExecutorService executorService = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 100; i++) {
            executorService.execute(new Task(i));
        }

        executorService.awaitTermination(11, SECONDS);

        executorService.shutdownNow();
        System.out.println(executorService);

Ing pungkasan, kita bakal nampilake informasi babagan kahanan executorService .

Mangkene output konsol sing kita entuk:

Panjaluk pangguna sing wis diproses #0 ing thread pool-1-thread-1
Panjaluk pangguna sing diproses #2 ing thread pool-1-thread-3
Panjaluk pangguna sing diproses #1 ing thread pool-1-thread-2
Panjaluk pangguna sing diproses #4 ing pool- Utas 1-thread-3
Panjaluk pangguna sing wis diproses #5 ing pool-1-thread-2 thread
Panjaluk pangguna sing diproses #3 ing pool-1-thread-1 thread
Panyuwunan pangguna sing diproses #6 ing pool-1-thread-3 thread
Pangguna sing diproses request #7 ing pool-1-thread-2 thread
Panjaluk pangguna sing wis diproses #8 ing pool-1-thread-1 thread
Panjaluk pangguna sing diproses #9 ing pool-1-thread-3 thread
Panjaluk pangguna sing diproses #11 ing pool-1- thread-1 thread
Panjaluk pangguna sing diproses #10 ing pool-1-thread-2 thread
Panjaluk pangguna sing diproses #13 ing pool-1-thread-1 thread
Panjaluk pangguna sing diproses #14 ing thread pool-1-thread-2
Panjaluk pangguna sing diproses #12 ing thread pool-1-thread-3
java.util.concurrent.ThreadPoolExecutor@452b3a41[Mateni, ukuran kolam = 3, utas aktif = 3 , tugas antri = 0, tugas rampung = 15]
Panjalukan pangguna sing diproses #17 ing thread pool-1-thread-3
Panjaluk pangguna sing diproses #15 ing thread-1-thread-1 thread
Panjaluk pangguna sing diproses #16 ing pool-1-thread -2 benang

Iki diikuti dening 3 InterruptedExceptions , dibuwang kanthi cara turu saka 3 tugas aktif.

Kita bisa ndeleng manawa program rampung, 15 tugas wis rampung, nanging blumbang isih duwe 3 utas aktif sing durung rampung nglakokake tugase. Cara interrupt () diarani ing telung utas iki, tegese tugas bakal rampung, nanging ing kasus kita, metode turu mbuwang InterruptedException . Kita uga weruh yen sawise shutdownNow () cara disebut, antrian tugas dibusak.

Dadi nalika nggunakake ExecutorService kanthi jumlah benang sing tetep ing blumbang, mesthine kudu ngelingi cara kerjane. Jinis iki cocok kanggo tugas kanthi beban konstan sing dikenal.

Mangkene pitakonan liyane sing menarik: yen sampeyan kudu nggunakake eksekutor kanggo thread siji, cara apa sampeyan kudu nelpon? newSingleThreadExecutor() utawa newFixedThreadPool(1) ?

Loro-lorone eksekutor bakal duwe prilaku sing padha. Bentenipun mung sing cara newSingleThreadExecutor () bakal ngasilake eksekutor sing ora bisa mengko reconfigured kanggo nggunakake Utas tambahan.