Jonny Karlsson PROCESSPROGRAMMERING Föreläsning 2 ( ) Innehåll:Trådar: - Avbrott (”interrupts”) - Metoden join() Högnivå objekt för trådprogrammering: - Trådgrupper (”Thread pools”) - Exekverare (”Executor” och ”ExecutorService”)
Jonny Karlsson Avbrott Ett avbrott är en signal till en tråd om att den borde avsluta det den gör just nu. Vanligast är att ett avbrott avslutar en tråd, men det är upp till programmeraren själv vad som skall ske när ett avbrott uppstår. En tråd kan skicka ett avbrott till en annan tråd genom att anropa metoden interrupt() som är definierad i klassen Thread (Se API specificationen).. //skapar och startar en tråd Thread th = new Thread(this); th.start();.. //gör någonting.. //Skickar ett avbrott till tråden th.interrupt();
Jonny Karlsson Avbrott Hur en tråd reagerar på ett avbrott beror på vad tråden gör just vid den tidpunkt ett avbrott uppstår. Om en tråd vid jämna mellanrum anropar metoder som kastar InterruptedException kan trådens run-metod programmeras att returnera genast efter att den fångat upp undantaget:while(true){ //gör något..try{Thread.sleep(1000);} catch(InterruptedException e) { //Denna tråd blev avbruten return 0; }}
Jonny Karlsson Avbrott Många metoder som kastar InterruptedException (t.ex. sleep()) är designade på ett sådant sätt att de avbryter sin nuvarande funktion och returnerar genast när ett avbrott tagits emot. Om en tråd utför någonting för en lång tid utan att anropa en metod som kastar InterruptedException måste den periodvis kolla om den blivit avbruten för att kunna stöda avbrott. Metoden interrupted() i klassen Thread returnerar true om innevarande tråd har tagit emot ett avbrott.
Jonny Karlsson Avbrott Exempel:while(true){System.out.println(”HelloWorld!!!!!”);if(Thread.interrupted()){ System.out.println(”Denna tråd tog emot ett avbrott!!”); return;}} Koden ovan helt enkelt returnerar och avslutar tråden om den tar emot ett avbrott.
Jonny Karlsson Avbrott Avbrottsmekanismen är implementerad genom att använda en flagga: interrupt status. När man anropar metoden interrupt() aktiveras flaggan interrupted status för den tråd man utförde interrupt() på. När en tråd kollar om den blivit avbruten med Thread.interrupted() kontrolleras det om flaggan är aktiverad eller ej och om den är aktiverad så kommer flaggan igen att bli inaktiv.
Jonny Karlsson Avbrott En tråd kan kontrollera om en annan tråd har tagit emot ett avbrott eller ej med metoden isInterrupted(): if(trad.isInterrupted()) //tråden trad har tagit emot ett avbrott else//tråden trad är fortfarande aktiv OBS! isInterrupted() ändrar inte statuset på flaggan interrupted status.
Jonny Karlsson Metoden join() Metoden join (definierad i klassen thread) tillåter en tråd att vänta på att en annan tråd skall avsluta sin exekvering. Exempel:... //trad är en tråd som för tillfället exekverar trad.join()... I koden ovan ställs innevarande tråd in att vänta på att tråden trad skall avslutas innan den fortsätter sin egen exekvering.
Jonny Karlsson Högnivå objekt för trådprogrammering Vi har hittils tittat på lågnivå APIn för trådprogrammering som funnits inbyggda i Java platformen nästan sedan första början. Trådprogrammering med lågnivå API är lämpligt för mindre program som inte har så många samtidigt exekverande trådar. Att skapa ett ny tråd via ett Thread objekt är dock relativt resurskrävande eftersom det innebär en interaktion med operativsystemet. Av den orsaken lönar det sej att använda sej av en annan lösning vid programmering av program som behöver skapa massvis med kortlivade trådar.
Jonny Karlsson Högnivå objekt för trådprogrammering Högnivå objekt för samtidighet ”concurrency” har funnits med i Java plattformen sedan 5.0 Dessa högnivåobjekt är resurssnålare än ”lågnivåtrådhantering” och klarar också av att utnyttja dagens multi-processor system. Användning av högnivå objekt för programmering av samtidighet innebär i praktiken användning av trådgrupper (”thread pools”)
Jonny Karlsson Trådgrupper En trådgrupp består av ett antal inaktiva trådar som är redo att exekvera när som helst. När en ny tråd behövs i ett program skapar man och startar inte en ny tråd utan man ger ett Runnable objekt till trådgruppen vartefter en av de inaktiva trådarna aktiveras och anropar run-metoden. När run-metoden returnerar (avslutas= stängs inte tråden av utan den hänger kvar som inaktiv och väntar på följande anrop.
Jonny Karlsson Trådgrupper En vanlig typ av trådgrupp som användes är fasta trådgrupper (”fixed thread pools”) Denna trådgruppstyp har alltid ett specifikt antal inaktiva trådar som är redo för exekvering. Uppgifter som skall utföras försätts i en kö om alla trådar i trådgruppen är upptagna. En fördel med att använda en fast trådgrupp är att det hindra ett program som använder sej av en massa trådar från att krascha (tänk dej en web-server applikation)
Jonny Karlsson Exekverare Trådgrupper kan användas via en viss typ av objekt som kallas för exekverare (”executors”) Java definierar bl.a. gränssnitten, Executor och ExecutorService, som stöder användning av trådgrupper Låt oss börja med att titta på gränssnittet Executor. Gränssnittet Executor erbjuder en ända metod: execute() Med denna metod kan man ta i bruk en inaktiv tråd i en trådgrupp.
Jonny Karlsson Exekverare: Executor Om r är ett Runnable objekt skapade man en ny tråd enligt lågnivåmodellen så här: th = new Thread(r); th.start(); Vid användning av executors kan koden ovan ersättas med (e är ett objekt av en Executor): Executor):e.execute(r); Kodraden ovan är egentligen ganska odefinierad. Vi har berättat att vi vill exekvera koden i run-metoden av ett Runnable objekt i en tråd men har inte berättat hurdan typ av tråd.
Jonny Karlsson Exekverare : Executor Med execute-metoden kan man också köra en uppgift i en egen skapad tråd. Men vi vill nu kanske hellre använda oss av en tråd ur en trådgrupp för att göra ett effektivt program. Java definierar en klass Executors som har ett antal statiska metoder för att skapa trådgrupper: trådgrupper:newCachedThreadPoosnewFixedThreadPoolnewSingleThreadExecutornewScheduledThreadPoolnewSingleThreadScheduledExecutor Se Java API dokumentationen för närmare info:
Jonny Karlsson Exekverare : Executor Man måste alltså börja med att skapa en trådgrupp. En trådgrupp med ett fast antal trådar kan man skapa m.h.a. den statiska metoden newFixedThreadPool() i klassen Executors: Executors.newFixedThreadPool(int nThreads); ExecutorService = En typ av Executorgränssnitt nThreads= Maxantalet trådar i trådgruppen Returnerar= Ett objekt av ett trådgränssnitt (Executor/ExecutorService)
Jonny Karlsson Exekverare : Executor Exempel: Skaper en trådgrupp på max 10 trådar och för över en uppgift till en tråd i trådgruppen class trad implemnts Runnable { public void run() { System.out.println(”Jag är en tråd!”); }... Executor tradgrupp = Executors.newFixedThreadPool(10) ; tradgrupp.execute(new Runnable()); }
Jonny Karlsson Exekverare: ExecutorService Gränssnittet ExecutorService erbjuder mera möjligheter när det gäller trådhantering än gränssnittet Executor Några av metoderna i gränssnittet ExecutorService: submit()= Används för att överföra koden i run-metdoen av ett Runnable ojbket till en tråd i en tidigare skapad trådgrupp shutdown() =Stänger en trådgrupp. Tillåter uppgiter som redan är skickade till trådgruppen att exekvera färdigt men nya trådar får inte längre aktiveras med submit(). shutdownNow() =Stänger av alla aktiva exekverande uppgifter i trådgruppen och stoppar även kön för väntande uppgifter. Returnerar en lista på de uppgifter som väntade på att få exekvera.
Jonny Karlsson Exekverare : ExecutorService Mera detaljer om metoden submit(): Future submit(Runnable task) Future submit(Runnable task, T result) Submit() är en överlagrad metod med bl.a. ovannämnda två alternativ. Båda alternativen tar ett Runnable objekt som parameter och returnerar ett Future – objekt. Future-objetet kan användas för att kolla olika statusinfo om den exekverande uppgiften, Se:
Jonny Karlsson Exekverare : ExecutorService Principen för användning av trådgrupper m.h.a. Gränssnittet ExecutorService är följande: Anropa en metod, t.ex. newFixedThreadPool i klassen Executors för att skapa en trådgrupp Anropa submit för att överföra en uppgift (koden i run-metoden av ett Runnable- objekt) till en tråd i den skapade trådgruppen Om du vill t.ex. kolla statusinfo eller avbryta en uppgift använd Future-objektets metoder. Anropa shutdown() när du inte längre kommer att submittera uppgifter till trådgruppen, m.a.o. Trådgruppen behövs ej längre
Jonny Karlsson Exekverare : ExecutorService Future-objektets metoder är: Cancel()= Försöker avbryta en uppgift i denna tråd Get()= Väntar på att tråden skall avslutas och om tråduppgiften (run-metoden) returnerar ett värde tad det emot i den formen som specifiserats mellan <> isCancelled()=Returnerar true om uppgiften avbröts före den blev klar isDone() =Returnerar true om uppgiften i en tråd är klar