Jinis liyane blumbang thread "cached". Kolam benang kaya biasane digunakake minangka sing tetep.

Kaya sing dituduhake kanthi jeneng, blumbang benang iki nyimpen benang. Utas sing ora digunakake tetep urip sajrone wektu winates supaya bisa nggunakake maneh benang kasebut kanggo nindakake tugas anyar. Kolam Utas kuwi paling apik kanggo nalika kita duwe sawetara cukup karya cahya.

Makna "sawetara jumlah sing cukup" cukup jembar, nanging sampeyan kudu ngerti manawa blumbang kasebut ora cocog kanggo saben tugas. Contone, umpamane kita pengin nggawe jutaan tugas. Sanajan saben njupuk wektu sing sithik, kita isih bakal nggunakake sumber daya sing ora wajar lan ngrusak kinerja. Kita uga kudu ngindhari pools kasebut nalika wektu eksekusi ora bisa ditebak, contone, karo tugas I / O.

Ing hood, konstruktor ThreadPoolExecutor diarani kanthi argumen ing ngisor iki:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
      new SynchronousQueue<Runnable>());
}

Nilai ing ngisor iki diterusake menyang konstruktor minangka argumen:

Paramèter Nilai
corePoolSize (pira thread bakal siap (diwiwiti) nalika layanan eksekutor diwiwiti) 0
maximumPoolSize (jumlah maksimum utas sing bisa digawe dening layanan eksekutor ) Integer.MAX_VALUE
keepAliveTime (wektu benang sing dibebasake bakal terus urip sadurunge dirusak yen jumlah benang luwih akeh tinimbang corePoolSize ) 60L
unit (unit wektu) TimeUnit.SECONDS
workQueue (implementasine antrian) anyar SynchronousQueue<Runnable>()

Lan kita bisa ngliwati implementasine ThreadFactory kanthi cara sing padha.

Ayo dadi pirembagan bab SynchronousQueue

Ide dhasar saka transfer sinkron cukup prasaja nanging kontra-intuisi (yaiku, intuisi utawa akal sehat ngandhani yen iku salah): sampeyan bisa nambah unsur menyang antrian yen lan mung yen thread liyane nampa unsur ing Sanalika. Ing tembung liyane, antrian sinkron ora bisa duwe tugas, amarga sanalika tugas anyar teka, utas pelaksana wis njupuk tugas .

Nalika tugas anyar lumebu ing antrian, yen ana free Utas aktif ing blumbang, banjur njupuk munggah tugas. Yen kabeh utas sibuk, banjur thread anyar digawe.

Kolam sing di-cache diwiwiti kanthi nol benang lan bisa tuwuh dadi benang Integer.MAX_VALUE . Ateges, ukuran blumbang thread cache mung diwatesi dening sumber daya sistem.

Kanggo ngirit sumber daya sistem, kumpulan benang sing di-cache mbusak benang sing ora aktif sajrone semenit.

Ayo ndeleng cara kerjane ing praktik. Kita bakal nggawe kelas tugas sing nggawe model panyuwunan pangguna:

public class Task implements Runnable {
   int taskNumber;

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

   @Override
   public void run() {
       System.out.println("Processed user request #" + taskNumber + " on thread " + Thread.currentThread().getName());
   }
}

Ing cara utama , kita nggawe newCachedThreadPool banjur nambah 3 tugas kanggo eksekusi. Ing kene kita nyithak status layanan kita (1) .

Sabanjure, kita ngaso 30 detik, miwiti tugas liyane, lan nampilake status (2) .

Sawisé iku, kita ngaso thread utama kita kanggo 70 detik, print status (3) , banjur maneh nambah 3 tugas, lan maneh print status (4) .

Ing panggonan ngendi kita nampilake status sanalika sawise nambah tugas, kita pisanan nambah turu 1 detik kanggo output up-to-date.

ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 3; i++) {
            executorService.submit(new Task(i));
        }

        TimeUnit.SECONDS.sleep(1);
            System.out.println(executorService);	//(1)

        TimeUnit.SECONDS.sleep(30);

        executorService.submit(new Task(3));
        TimeUnit.SECONDS.sleep(1);
            System.out.println(executorService);	//(2)

        TimeUnit.SECONDS.sleep(70);

            System.out.println(executorService);	//(3)

        for (int i = 4; i < 7; i++) {
            executorService.submit(new Task(i));
        }

        TimeUnit.SECONDS.sleep(1);
            System.out.println(executorService);	//(4)
        executorService.shutdown();

Lan iki asile:

Panjaluk pangguna sing diproses #0 ing thread pool-1-thread-1
Panjaluk pangguna sing diproses #1 ing thread pool-1-thread-2
Panjaluk pangguna sing diproses #2 ing thread pool-1-thread-3
(1) java.util.concurrent .ThreadPoolExecutor@f6f4d33[Mlaku, ukuran blumbang = 3, Utas aktif = 0, tugas queued = 0, tugas rampung = 3]
Diproses request pangguna # 3 ing pool-1-thread-2 thread
(2) java.util.concurrent. ThreadPoolExecutor@f6f4d33[Mlaku, ukuran blumbang = 3, utas aktif = 0, tugas antri = 0, tugas rampung = 4]
(3) java.util.concurrent.ThreadPoolExecutor@f6f4d33[Mlaku, ukuran blumbang = 0, utas aktif = 0 , tugas antri = 0, tugas rampung = 4]
Panjaluk pangguna sing diproses #4 ing thread pool-1-thread-4
Panjaluk pangguna sing diproses #5 ing thread pool-1-thread-5
Panjaluk pangguna sing diproses #6 ing thread pool-1-thread-4
(4) java.util.concurrent.ThreadPoolExecutor@f6f4d33[Mlaku, ukuran blumbang = 2, utas aktif = 0, tugas antri = 0, tugas rampung = 7]

Ayo pindhah liwat saben langkah:

Langkah Panjelasan
1 (sawise 3 tugas rampung) Kita nggawe 3 utas, lan 3 tugas dieksekusi ing telung utas kasebut.
Nalika status ditampilake, kabeh 3 tugas wis rampung, lan thread siap kanggo nindakake tugas liyane.
2 (sawise ngaso 30 detik lan nglakokake tugas liyane) Sawise 30 detik ora aktif, benang isih urip lan ngenteni tugas.
Tugas liyane ditambahake lan dieksekusi ing benang sing dijupuk saka blumbang benang urip sing isih ana.
Ora ana thread anyar sing ditambahake menyang blumbang.
3 (sawise ngaso 70 detik) Utas wis dibusak saka blumbang.
Ora ana utas sing siap nampa tugas.
4 (sawise nindakake 3 tugas liyane) Sawise luwih akeh tugas ditampa, utas anyar digawe. Wektu iki mung rong utas sing bisa ngolah 3 tugas.

Inggih, saiki sampeyan wis ngerti logika saka jinis layanan eksekutor liyane.

Kanthi analogi karo metode liyane saka kelas utilitas Executors , metode newCachedThreadPool uga nduweni versi sing overloaded sing njupuk obyek ThreadFactory minangka argumen.