Zoeken…


Invoering

De Executor- interface in Java biedt een manier om taakverzending te ontkoppelen van de mechanica van hoe elke taak wordt uitgevoerd, inclusief details van threadgebruik, planning, enz. Normaal wordt een Executor gebruikt in plaats van expliciet threads te maken. Met Executors hoeven ontwikkelaars hun code niet aanzienlijk te herschrijven om het taakuitvoeringsbeleid van hun programma gemakkelijk te kunnen afstemmen.

Opmerkingen

valkuilen

  • Wanneer u een taak plant voor herhaalde uitvoering, afhankelijk van de gebruikte ScheduledExecutorService, kan uw taak worden opgeschort voor verdere uitvoering, als een uitvoering van uw taak een uitzondering veroorzaakt die niet wordt afgehandeld. Zie moeder F ** k de ScheduledExecutorService!

Vuur en vergeet - Uit te voeren taken

Uitvoerders accepteren een java.lang.Runnable die (mogelijk rekenkundig of anderszins langlopende of zware) code bevat die in een andere thread moet worden uitgevoerd.

Gebruik zou zijn:

Executor exec = anExecutor;
exec.execute(new Runnable() {
    @Override public void run() {
        //offloaded work, no need to get result back
    }
});

Merk op dat je met deze uitvoerder geen middelen hebt om enige berekende waarde terug te krijgen.
Met Java 8 kan men lambdas gebruiken om het codevoorbeeld in te korten.

Java SE 8
Executor exec = anExecutor;
exec.execute(() -> {
    //offloaded work, no need to get result back
});

ThreadPoolExecutor

Een veelgebruikte uitvoerder is de ThreadPoolExecutor , die zorgt voor de verwerking van de threads. U kunt het minimale aantal threads configureren dat de uitvoerder altijd moet onderhouden als er niet veel te doen is (dit wordt kerngrootte genoemd) en een maximale threadgrootte waarnaar de pool kan groeien, als er meer werk is. Zodra de werklast afneemt, vermindert de pool langzaam het aantal threads opnieuw totdat het de minimale grootte bereikt.

ThreadPoolExecutor pool = new ThreadPoolExecutor(
    1,                                     // keep at least one thread ready, 
                                           // even if no Runnables are executed
    5,                                     // at most five Runnables/Threads
                                           // executed in parallel
    1, TimeUnit.MINUTES,                   // idle Threads terminated after one
                                           // minute, when min Pool size exceeded
    new ArrayBlockingQueue<Runnable>(10)); // outstanding Runnables are kept here

pool.execute(new Runnable() {
    @Override public void run() {
        //code to run
    }
});

Opmerking Als u de ThreadPoolExecutor configureert met een onbeperkte wachtrij, overschrijdt het corePoolSize threads corePoolSize omdat nieuwe threads alleen worden gemaakt als de wachtrij vol is:

ThreadPoolExecutor met alle parameters:

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)

van JavaDoc

Als er meer dan corePoolSize maar minder dan maximumPoolSize threads worden uitgevoerd, wordt alleen een nieuwe thread gemaakt als de wachtrij vol is.

voordelen:

  1. BlockingQueue-grootte kan worden geregeld en scenario's met onvoldoende geheugen kunnen worden voorkomen. Applicatieprestaties worden niet verslechterd met een beperkte begrensde wachtrijgrootte.

  2. U kunt bestaande gebruiken of een nieuw Rejection Handler-beleid maken.

    1. In de standaard ThreadPoolExecutor.AbortPolicy gooit de handler een runtime RejectedExecutionException na afwijzing.

    2. In ThreadPoolExecutor.CallerRunsPolicy wordt de taak uitgevoerd door de thread die zichzelf uitvoert. Dit biedt een eenvoudig feedbackcontrolemechanisme dat het aantal nieuwe taken vertraagt.

    3. In ThreadPoolExecutor.DiscardPolicy wordt een taak die niet kan worden uitgevoerd eenvoudig verwijderd.

    4. In ThreadPoolExecutor.DiscardOldestPolicy , als de uitvoerder niet wordt afgesloten, wordt de taak aan het hoofd van de werkwachtrij verwijderd en wordt de uitvoering opnieuw geprobeerd (wat opnieuw kan mislukken, waardoor dit wordt herhaald.)

  3. Custom ThreadFactory kan worden geconfigureerd, wat handig is:

    1. Om een meer beschrijvende threadnaam in te stellen
    2. De thread-daemonstatus instellen
    3. Draadprioriteit instellen

Hier is een voorbeeld van het gebruik van ThreadPoolExecutor

Waarde ophalen uit berekening - op te roepen

Als uw berekening een bepaalde retourwaarde oplevert die later vereist is, is een eenvoudige uitvoerbare taak niet voldoende. In dergelijke gevallen kunt u ExecutorService.submit( Callable <T>) die een waarde retourneert nadat de uitvoering is voltooid.

De service retourneert een Future die u kunt gebruiken om het resultaat van de uitvoering van de taak op te halen.

// Submit a callable for execution
ExecutorService pool = anExecutorService;
Future<Integer> future = pool.submit(new Callable<Integer>() {
    @Override public Integer call() {
        //do some computation
        return new Random().nextInt();
    }
});    
// ... perform other tasks while future is executed in a different thread

Als u het resultaat van de toekomst nodig hebt, belt u future.get()

  • Wacht onbeperkt tot de toekomst met een resultaat eindigt.

      try {
          // Blocks current thread until future is completed
          Integer result = future.get(); 
      catch (InterruptedException || ExecutionException e) {
          // handle appropriately
      }
    
  • Wacht tot de toekomst is voltooid, maar niet langer dan de opgegeven tijd.

      try {
          // Blocks current thread for a maximum of 500 milliseconds.
          // If the future finishes before that, result is returned,
          // otherwise TimeoutException is thrown.
          Integer result = future.get(500, TimeUnit.MILLISECONDS); 
      catch (InterruptedException || ExecutionException || TimeoutException e) {
          // handle appropriately
      }
    

Als het resultaat van een geplande of actieve taak niet langer vereist is, kunt u Future.cancel(boolean) bellen om deze te annuleren.

  • Als cancel(false) belt cancel(false) wordt de taak gewoon verwijderd uit de wachtrij die moet worden uitgevoerd.
  • Als cancel(true) aanroept, wordt de taak ook onderbroken als deze momenteel wordt uitgevoerd.

Plannen dat taken op een vast tijdstip, na een vertraging of herhaaldelijk worden uitgevoerd

De klasse ScheduledExecutorService biedt een methode voor het plannen van enkele of herhaalde taken op een aantal manieren. In het volgende codevoorbeeld wordt ervan uitgegaan dat de pool als volgt is gedeclareerd en geïnitialiseerd:

ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);

Naast de normale ExecutorService methoden, voegt de API ScheduledExecutorService 4 methoden toe die taken plannen en objecten ScheduledFuture retourneren. Dit laatste kan worden gebruikt om (in sommige gevallen) resultaten op te halen en taken te annuleren.

Een taak starten na een vaste vertraging

In het volgende voorbeeld wordt een taak gepland om na tien minuten te starten.

ScheduledFuture<Integer> future = pool.schedule(new Callable<>() {
        @Override public Integer call() {
            // do something
            return 42;
        }
    }, 
    10, TimeUnit.MINUTES);

Taken starten tegen een vast tarief

In het volgende voorbeeld wordt een taak gepland om na tien minuten te starten en vervolgens herhaaldelijk met een snelheid van één keer per minuut.

ScheduledFuture<?> future = pool.scheduleAtFixedRate(new Runnable() {
        @Override public void run() {
            // do something
        }
    }, 
    10, 1, TimeUnit.MINUTES);

De uitvoering van de taak zal doorgaan volgens het schema totdat de pool wordt afgesloten, de future wordt geannuleerd of een van de taken op een uitzondering stuit.

Het is gegarandeerd dat de taken die zijn gepland met een bepaalde scheduledAtFixedRate oproep elkaar niet op tijd overlappen. Als een taak langer duurt dan de voorgeschreven periode, kunnen de volgende en volgende taakuitvoering te laat beginnen.

Taken starten met een vaste vertraging

In het volgende voorbeeld wordt een taak gepland om na tien minuten te starten en vervolgens herhaaldelijk met een vertraging van één minuut tussen het einde van de ene taak en het volgende.

ScheduledFuture<?> future = pool.scheduleWithFixedDelay(new Runnable() {
        @Override public void run() {
            // do something
        }
    }, 
    10, 1, TimeUnit.MINUTES);

De uitvoering van de taak zal doorgaan volgens het schema totdat de pool wordt afgesloten, de future wordt geannuleerd of een van de taken op een uitzondering stuit.

Afgewezen uitvoering verwerken

Als

  1. u probeert taken in te dienen bij een shutdown-uitvoerder of
  2. de wachtrij is verzadigd (alleen mogelijk met begrensde) en het maximale aantal threads is bereikt,

RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor) wordt aangeroepen.

Het standaardgedrag is dat een RejectedExecutionException naar de beller wordt gegooid. Maar er zijn meer vooraf gedefinieerde gedragingen beschikbaar:

  • ThreadPoolExecutor.AbortPolicy (standaard, gooit REE)
  • ThreadPoolExecutor.CallerRunsPolicy (voert taak uit op thread van beller - blokkeert deze )
  • ThreadPoolExecutor.DiscardPolicy (taak in stilte weggooien)
  • ThreadPoolExecutor.DiscardOldestPolicy (verwijder oudste taak in de wachtrij en probeer de nieuwe taak opnieuw uit te voeren)

Je kunt ze instellen met een van de ThreadPool- constructors :

public ThreadPoolExecutor(int corePoolSize,
                      int maximumPoolSize,
                      long keepAliveTime,
                      TimeUnit unit,
                      BlockingQueue<Runnable> workQueue,
                      RejectedExecutionHandler handler) // <--

public ThreadPoolExecutor(int corePoolSize,
                      int maximumPoolSize,
                      long keepAliveTime,
                      TimeUnit unit,
                      BlockingQueue<Runnable> workQueue,
                      ThreadFactory threadFactory,
                      RejectedExecutionHandler handler) // <--

Je kunt ook je eigen gedrag implementeren door de RejectedExecutionHandler- interface uit te breiden:

void rejectedExecution(Runnable r, ThreadPoolExecutor executor)

submit () vs execute () uitzonderingsafhandelingsverschillen

In het algemeen wordt het commando execute () gebruikt voor het vuur en vergeet oproepen (zonder het resultaat te analyseren) en het commando submit () wordt gebruikt voor het analyseren van het resultaat van het Future-object.

We moeten ons bewust zijn van het belangrijkste verschil tussen mechanismen voor het omgaan met uitzonderingen tussen deze twee opdrachten.

Uitzonderingen op submit () worden door het kader ingeslikt als u ze niet hebt gevangen.

Codevoorbeeld om het verschil te begrijpen:

Geval 1: dien de opdracht Runnable met execute () in, die de uitzondering meldt.

import java.util.concurrent.*;
import java.util.*;

public class ExecuteSubmitDemo {
    public ExecuteSubmitDemo() {
        System.out.println("creating service");
        ExecutorService service = Executors.newFixedThreadPool(2);
        //ExtendedExecutor service = new ExtendedExecutor();
        for (int i = 0; i < 2; i++){
            service.execute(new Runnable(){
                 public void run(){
                    int a = 4, b = 0;
                    System.out.println("a and b=" + a + ":" + b);
                    System.out.println("a/b:" + (a / b));
                    System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
                 }
            });
        }
        service.shutdown();
    }
    public static void main(String args[]){
        ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
    }
}

class ExtendedExecutor extends ThreadPoolExecutor {

   public ExtendedExecutor() { 
       super(1, 1, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
   }
   // ...
   protected void afterExecute(Runnable r, Throwable t) {
     super.afterExecute(r, t);
     if (t == null && r instanceof Future<?>) {
       try {
         Object result = ((Future<?>) r).get();
       } catch (CancellationException ce) {
           t = ce;
       } catch (ExecutionException ee) {
           t = ee.getCause();
       } catch (InterruptedException ie) {
           Thread.currentThread().interrupt(); // ignore/reset
       }
     }
     if (t != null)
       System.out.println(t);
   }
 }

output:

creating service
a and b=4:0
a and b=4:0
Exception in thread "pool-1-thread-1" Exception in thread "pool-1-thread-2" java.lang.ArithmeticException: / by zero
        at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:15)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)
java.lang.ArithmeticException: / by zero
        at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:15)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)

Geval 2: vervang execute () door submit (): service.submit(new Runnable(){ In dit geval worden uitzonderingen door het raamwerk ingeslikt omdat de methode run () ze niet expliciet heeft opgevangen.

output:

creating service
a and b=4:0
a and b=4:0

Geval 3: Wijzig de newFixedThreadPool in ExtendedExecutor

//ExecutorService service = Executors.newFixedThreadPool(2);
 ExtendedExecutor service = new ExtendedExecutor(); 

output:

creating service
a and b=4:0
java.lang.ArithmeticException: / by zero
a and b=4:0
java.lang.ArithmeticException: / by zero

Ik heb dit voorbeeld gedemonstreerd om twee onderwerpen te behandelen: Gebruik uw aangepaste ThreadPoolExecutor en behandel Exectpion met aangepaste ThreadPoolExecutor.

Andere eenvoudige oplossing voor het bovenstaande probleem: wanneer u de normale ExecutorService & submit-opdracht gebruikt, haalt u het Future-object uit de submit () opdrachtoproep get () API op Future. Vang de drie uitzonderingen, die zijn geciteerd in de implementatie van de methode AfterExecute. Voordeel van aangepaste ThreadPoolExecutor ten opzichte van deze aanpak: u hoeft het afhandelingsmechanisme voor uitzonderingen slechts op één plaats af te handelen - Custom ThreadPoolExecutor.

Gebruik cases voor verschillende soorten gelijktijdigheidsconstructies

  1. ExecutorService

    ExecutorService executor = Executors.newFixedThreadPool(50);

    Het is eenvoudig en gemakkelijk te gebruiken. Het verbergt details op laag niveau van ThreadPoolExecutor .

    Ik geef de voorkeur aan deze wanneer het aantal Callable/Runnable taken klein in aantal is en het stapelen van taken in onbeperkte wachtrij het geheugen niet verhoogt en de prestaties van het systeem verslechtert. Als u CPU/Memory , gebruik ik liever ThreadPoolExecutor met capaciteitsbeperkingen & RejectedExecutionHandler om afwijzing van taken af te handelen.

  2. CountDownLatch

    CountDownLatch wordt geïnitialiseerd met een bepaalde telling. Dit aantal wordt verlaagd door aanroepen van de methode countDown() . Threads die wachten tot deze telling nul bereikt, kunnen een van de await() methoden aanroepen. Het aanroepen van await() blokkeert de thread totdat de telling nul bereikt. Met deze klasse kan een Java-thread wachten tot een andere reeks threads hun taken heeft voltooid.

    Gebruik gevallen:

    1. Maximaal parallellisme bereiken: soms willen we een aantal threads tegelijkertijd starten om maximaal parallellisme te bereiken

    2. Wacht N threads om te voltooien voordat u de uitvoering start

    3. Deadlock-detectie.

  1. ThreadPoolExecutor : het biedt meer controle. Als de toepassing wordt beperkt door het aantal openstaande / opvraagbare taken die in behandeling zijn, kunt u de begrensde wachtrij gebruiken door de maximale capaciteit in te stellen. Zodra de wachtrij de maximale capaciteit bereikt, kunt u RejectionHandler definiëren. Java biedt vier soorten RejectedExecutionHandler beleid .

    1. ThreadPoolExecutor.AbortPolicy , de handler gooit een runtime RejectedExecutionException na afwijzing.

    2. ThreadPoolExecutor.CallerRunsPolicy`, de thread die zichzelf uitvoert voert de taak uit. Dit biedt een eenvoudig feedbackcontrolemechanisme dat het aantal nieuwe taken vertraagt.

    3. In ThreadPoolExecutor.DiscardPolicy wordt een taak die niet kan worden uitgevoerd eenvoudig verwijderd.

    4. ThreadPoolExecutor.DiscardOldestPolicy , als de uitvoerder niet wordt afgesloten, wordt de taak aan het begin van de werkwachtrij verwijderd en wordt de uitvoering opnieuw geprobeerd (wat opnieuw kan mislukken, waardoor dit wordt herhaald.)

Als u CountDownLatch gedrag wilt simuleren, kunt u de methode invokeAll() gebruiken.

  1. Nog een mechanisme dat u niet citeerde is ForkJoinPool

    De ForkJoinPool is toegevoegd aan Java in Java 7. De ForkJoinPool is vergelijkbaar met de Java ExecutorService maar met één verschil. De ForkJoinPool maakt het gemakkelijk voor taken om hun werk op te splitsen in kleinere taken die dan ook aan de ForkJoinPool worden voorgelegd. Het stelen van taken vindt plaats in ForkJoinPool wanneer vrije ForkJoinPool taken stelen uit de drukke wachtrij voor werkthreads.

    Java 8 heeft nog een API in ExecutorService geïntroduceerd om werkstelenpool te creëren. Je hoeft niet te maken RecursiveTask en RecursiveAction maar kan nog steeds gebruik maken van ForkJoinPool .

    public static ExecutorService newWorkStealingPool()
    

    Creëert een werkstelende threadpool met alle beschikbare processors als doelparallelliteitsniveau.

    Standaard duurt het aantal CPU-cores als parameter.

Al deze vier mechanismen vullen elkaar aan. Afhankelijk van het niveau van granulariteit dat u wilt beheren, moet u de juiste kiezen.

Wacht tot alle taken in ExecutorService zijn voltooid

Laten we eens kijken naar verschillende opties om te wachten voor de voltooiing van de ingediende taken Uitvoerder

  1. ExecutorService invokeAll()

    Voert de gegeven taken uit en retourneert een lijst met Futures met hun status en resultaten wanneer alles is voltooid.

Voorbeeld:

import java.util.concurrent.*;
import java.util.*;

public class InvokeAllDemo{
    public InvokeAllDemo(){
        System.out.println("creating service");
        ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        
        List<MyCallable> futureList = new ArrayList<MyCallable>();
        for (int i = 0; i < 10; i++){
            MyCallable myCallable = new MyCallable((long)i);
            futureList.add(myCallable);
        }
        System.out.println("Start");
        try{
            List<Future<Long>> futures = service.invokeAll(futureList);  
        } catch(Exception err){
            err.printStackTrace();
        }
        System.out.println("Completed");
        service.shutdown();
    }
    public static void main(String args[]){
        InvokeAllDemo demo = new InvokeAllDemo();
    }
    class MyCallable implements Callable<Long>{
        Long id = 0L;
        public MyCallable(Long val){
            this.id = val;
        }
        public Long call(){
            // Add your business logic
            return id;
        }
    }
}
  1. CountDownLatch

    Een synchronisatiehulpmiddel waarmee een of meer threads kunnen wachten tot een reeks bewerkingen die in andere threads worden uitgevoerd, is voltooid.

    Een CountDownLatch wordt geïnitialiseerd met een bepaalde telling. De methoden wachten wachten tot de huidige telling nul bereikt vanwege aanroepen van de methode countDown() , waarna alle wachtende threads worden vrijgegeven en alle daaropvolgende aanroepen van wachten onmiddellijk terugkeren. Dit is een eenmalig verschijnsel - de telling kan niet worden gereset. Als u een versie nodig hebt die de telling opnieuw instelt , kunt u overwegen een CyclicBarrier te gebruiken .

  2. ForkJoinPool of newWorkStealingPool() in Executors

  3. Doorloop alle Future objecten die zijn gemaakt na verzending naar ExecutorService

  4. Aanbevolen manier om de Oracle-documentatiepagina van ExecutorService af te sluiten :

    void shutdownAndAwaitTermination(ExecutorService pool) {
        pool.shutdown(); // Disable new tasks from being submitted
        try {
          // Wait a while for existing tasks to terminate
          if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
            pool.shutdownNow(); // Cancel currently executing tasks
            // Wait a while for tasks to respond to being cancelled
            if (!pool.awaitTermination(60, TimeUnit.SECONDS))
                System.err.println("Pool did not terminate");
          }
        } catch (InterruptedException ie) {
          // (Re-)Cancel if current thread also interrupted
          pool.shutdownNow();
          // Preserve interrupt status
          Thread.currentThread().interrupt();
        }
    

    shutdown(): Start een geordende afsluiting waarin eerder ingediende taken worden uitgevoerd, maar geen nieuwe taken worden geaccepteerd.

    shutdownNow(): Pogingen om alle actief uitgevoerde taken te stoppen, stopt de verwerking van wachtende taken en retourneert een lijst met taken die in afwachting waren van uitvoering.

    Als in het bovenstaande voorbeeld meer tijd nodig is om uw taken uit te voeren, kunt u de voorwaarde wijzigen in de voorwaarde voorwaarde

    Vervangen

    if (!pool.awaitTermination(60, TimeUnit.SECONDS))
    

    met

    while(!pool.awaitTermination(60, TimeUnit.SECONDS)) {
      Thread.sleep(60000);
    

    }

Gebruik cases voor verschillende soorten ExecutorService

Executors retourneert een ander type ThreadPools voor specifieke behoeften.

  1. public static ExecutorService newSingleThreadExecutor()

    Maakt een uitvoerder die een enkele werkthread gebruikt die werkt vanuit een onbeperkte wachtrij

    Er is een verschil tussen newFixedThreadPool(1) en newSingleThreadExecutor() zoals de java-doc voor de laatste zegt:

    In tegenstelling tot de overigens equivalente newFixedThreadPool (1) is de geretourneerde uitvoerder gegarandeerd niet herconfigureerbaar om extra threads te gebruiken.

    Wat betekent dat een newFixedThreadPool later in het programma opnieuw kan worden geconfigureerd door: ((ThreadPoolExecutor) fixedThreadPool).setMaximumPoolSize(10) Dit is niet mogelijk voor newSingleThreadExecutor

    Gebruik gevallen:

    1. U wilt de ingediende taken in een reeks uitvoeren.
    2. U hebt slechts één thread nodig om al uw verzoeken af te handelen

    nadelen:

    1. Onbeperkte wachtrij is schadelijk
  2. public static ExecutorService newFixedThreadPool(int nThreads)

    Creëert een thread pool die een vast aantal threads hergebruikt die werken vanuit een gedeelde onbegrensde wachtrij. Op elk moment zullen de meeste nThreads-threads actieve verwerkingstaken zijn. Als er extra taken worden verzonden wanneer alle threads actief zijn, wachten ze in de wachtrij totdat er een thread beschikbaar is

    Gebruik gevallen:

    1. Effectief gebruik van beschikbare kernen. nThreads als Runtime.getRuntime().availableProcessors()
    2. Wanneer u besluit dat aantal threads niet hoger mag zijn dan een nummer in de threadpool

    nadelen:

    1. Onbeperkte wachtrij is schadelijk.
  3. public static ExecutorService newCachedThreadPool()

    Hiermee maakt u een threadpool die indien nodig nieuwe threads maakt, maar eerder geconstrueerde threads opnieuw gebruikt wanneer deze beschikbaar zijn

    Gebruik gevallen:

    1. Voor asynchrone taken van korte duur

    nadelen:

    1. Onbeperkte wachtrij is schadelijk.
    2. Elke nieuwe taak maakt een nieuwe thread als alle bestaande threads bezet zijn. Als de taak lang duurt, worden er meer threads gemaakt, waardoor de prestaties van het systeem achteruitgaan. Alternatief in dit geval: newFixedThreadPool
  1. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

    Hiermee maakt u een threadpool die kan plannen dat opdrachten na een bepaalde vertraging worden uitgevoerd of periodiek worden uitgevoerd.

    Gebruik gevallen:

    1. Omgaan met terugkerende gebeurtenissen met vertragingen, die in de toekomst op bepaalde tijdstippen zullen gebeuren

    nadelen:

    1. Onbeperkte wachtrij is schadelijk.

    5. public static ExecutorService newWorkStealingPool()

    Creëert een werkstelende threadpool met alle beschikbare processors als doelparallelliteitsniveau

    Gebruik gevallen:

    1. Voor het verdelen en overwinnen van soort problemen.
    2. Effectief gebruik van niet-actieve threads. Niet-actieve threads steelt taken van drukke threads.

    nadelen:

    1. Onbeperkte wachtrijgrootte is schadelijk.

U kunt een van de vele nadelen zien in al deze ExecutorService: onbeperkte wachtrij. Dit wordt aangepakt met ThreadPoolExecutor

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)

Met ThreadPoolExecutor kunt u dat

  1. Beheer de schroefdraadpool dynamisch
  2. Stel de capaciteit in voor BlockingQueue
  3. Definieer RejectionExecutionHander wanneer de wachtrij vol is
  4. CustomThreadFactory om wat extra functionaliteit toe te voegen tijdens het maken van een thread (public Thread newThread(Runnable r)

Thread Pools gebruiken

Thread Pools worden meestal gebruikt in ExecutorService .

De volgende methoden kunnen worden gebruikt om werk in te dienen voor uitvoering:

Methode Beschrijving
submit Voert het ingediende werk uit en retourneert een toekomst die kan worden gebruikt om het resultaat te krijgen
execute Voer de taak ergens in de toekomst uit zonder enige retourwaarde te krijgen
invokeAll Voer een lijst met taken uit en retourneer een lijst met Futures
invokeAny Voert alles uit, maar retourneert alleen het resultaat van een resultaat dat succesvol is (zonder uitzonderingen)

Als je klaar bent met de threadpool, kun je shutdown() gebruiken om de threadpool te beëindigen. Hiermee worden alle taken in behandeling uitgevoerd. Om te wachten tot alle taken zijn uitgevoerd, kun je lus awaitTermination of isShutdown() .



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow