En anden type trådpulje er "cached". Sådanne trådpuljer er lige så almindeligt anvendte som faste.

Som angivet af navnet, cacher denne slags trådpulje tråde. Det holder ubrugte tråde i live i en begrænset periode for at genbruge disse tråde til at udføre nye opgaver. Sådan en trådpulje er bedst, når vi har noget rimeligt let arbejde.

Betydningen af ​​"en rimelig mængde" er ret bred, men du skal vide, at en sådan pulje ikke er egnet til alle opgaver. Antag for eksempel, at vi vil oprette en million opgaver. Selvom hver enkelt tager meget kort tid, vil vi stadig bruge en urimelig mængde ressourcer og forringe ydeevnen. Vi bør også undgå sådanne puljer, når eksekveringstiden er uforudsigelig, for eksempel med I/O-opgaver.

Under hætten kaldes ThreadPoolExecutor- konstruktøren med følgende argumenter:

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

Følgende værdier sendes til konstruktøren som argumenter:

Parameter Værdi
corePoolSize (hvor mange tråde vil være klar (startet), når executor -tjenesten starter) 0
maximumPoolSize (det maksimale antal tråde, som en eksekveringstjeneste kan oprette) Heltal.MAX_VALUE
keepAliveTime (det tidspunkt, hvor en frigivet tråd vil fortsætte med at leve, før den bliver ødelagt, hvis antallet af tråde er større end corePoolSize ) 60L
enhed (tidsenheder) TimeUnit.SECONDS
workQueue (implementering af en kø) ny SynchronousQueue<Runnable>()

Og vi kan videregive vores egen implementering af ThreadFactory på nøjagtig samme måde.

Lad os tale om SynchronousQueue

Den grundlæggende idé med en synkron overførsel er ganske enkel og alligevel kontraintuitiv (det vil sige, intuition eller sund fornuft fortæller dig, at det er forkert): du kan tilføje et element til en kø, hvis og kun hvis en anden tråd modtager elementet på samme tid. Med andre ord kan en synkron kø ikke have opgaver i sig, for så snart en ny opgave ankommer, har den udførende tråd allerede hentet opgaven .

Når en ny opgave kommer ind i køen, hvis der er en ledig aktiv tråd i puljen, så samler den opgaven op. Hvis alle tråde er optaget, oprettes en ny tråd.

En cachelagret pulje starter med nul tråde og kan potentielt vokse til heltal.MAX_VALUE tråde. Grundlæggende er størrelsen af ​​en cachelagret trådpulje kun begrænset af systemressourcer.

For at spare systemressourcer fjerner cachelagrede trådpuljer tråde, der er inaktive i et minut.

Lad os se, hvordan det fungerer i praksis. Vi opretter en opgaveklasse, der modellerer en brugeranmodning:

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

I hovedmetoden opretter vi newCachedThreadPool og tilføjer derefter 3 opgaver til udførelse. Her udskriver vi status for vores service (1) .

Dernæst holder vi pause i 30 sekunder, starter en anden opgave og viser status (2) .

Derefter pauser vi vores hovedtråd i 70 sekunder, udskriver status (3) , tilføjer derefter 3 opgaver igen og udskriver igen status (4) .

På steder, hvor vi viser status umiddelbart efter tilføjelse af en opgave, tilføjer vi først en 1-sekunds dvale for opdateret output.

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();

Og her er resultatet:

Behandlet brugeranmodning #0 på pool-1-thread-1 thread
Behandlet brugeranmodning #1 på pool-1-thread-2 thread
Behandlet brugeranmodning #2 på pool-1-thread-3 thread
(1) java.util.concurrent .ThreadPoolExecutor@f6f4d33[Kører, poolstørrelse = 3, aktive tråde = 0, opgaver i kø = 0, afsluttede opgaver = 3]
Behandlet brugeranmodning #3 på pool-1-tråd-2 tråd
(2) java.util.concurrent. ThreadPoolExecutor@f6f4d33[Kører, puljestørrelse = 3, aktive tråde = 0, opgaver i kø = 0, afsluttede opgaver = 4] (3)
java.util.concurrent.ThreadPoolExecutor@f6f4d33[Kører, poolstørrelse = 0, aktive tråde = 0 , opgaver i kø = 0, afsluttede opgaver = 4]
Behandlet brugeranmodning #4 på pool-1-thread-4-tråd
Behandlet brugeranmodning #5 på pool-1-thread-5-tråd
Behandlet brugeranmodning #6 på pool-1-thread-4 tråd
(4) java.util.concurrent.ThreadPoolExecutor@f6f4d33[Kører, poolstørrelse = 2, aktive tråde = 0, opgaver i kø = 0, afsluttede opgaver = 7]

Lad os gennemgå hvert af trinene:

Trin Forklaring
1 (efter 3 udførte opgaver) Vi oprettede 3 tråde, og 3 opgaver blev udført på disse tre tråde.
Når status vises, er alle 3 opgaver udført, og trådene er klar til at udføre andre opgaver.
2 (efter 30 sekunders pause og udførelse af en anden opgave) Efter 30 sekunders inaktivitet er trådene stadig i live og venter på opgaver.
En anden opgave tilføjes og udføres på en tråd taget fra puljen af ​​de resterende aktive tråde.
Der blev ikke tilføjet nogen ny tråd til puljen.
3 (efter en pause på 70 sekunder) Trådene er fjernet fra poolen.
Der er ingen tråde klar til at acceptere opgaver.
4 (efter at have udført yderligere 3 opgaver) Efter at flere opgaver var modtaget, blev der oprettet nye tråde. Denne gang lykkedes det kun to tråde at behandle 3 opgaver.

Nå, nu er du bekendt med logikken i en anden type eksekveringstjeneste.

Analogt med andre metoder i værktøjsklassen Executors har newCachedThreadPool -metoden også en overbelastet version, der tager et ThreadFactory -objekt som et argument.