concurrency java semaphore
Denne vejledning diskuterer komponenter i java.util.concurrent-pakken som Java Semaphore, Executor Framework, ExecutorService til implementering af Concurrency i Java:
Fra vores tidligere Java-tutorials ved vi, at Java-platformen understøtter samtidig programmering fra bunden. Den grundlæggende enhed af samtidighed er en tråd, og vi har diskuteret tråde og multithreading i Java i detaljer.
Fra Java 5 og fremefter blev en pakke kaldet 'java.util.concurrent' tilføjet til Java-platformen. Denne pakke indeholder et sæt klasser og biblioteker, der gør det lettere for programmøren at udvikle samtidige (multi-threaded) applikationer. Ved hjælp af denne pakke behøver vi ikke skrive komplekse klasser, da vi har klar implementeringer af de fleste af de samtidige koncepter.
=> Tjek ALLE Java-tutorials her.
I denne vejledning vil vi diskutere de forskellige komponenter i pakken java.util.concurrent vedrørende samtidighed og multithreading i Java.
Hvad du vil lære:
java.util.conconurrent pakke
Nedenfor er de forskellige komponenter i pakken java.util.concurrent angående samtidighed og multithreading i Java. Lad os udforske hver komponent i detaljer ved hjælp af enkle programmeringseksempler. Nogle af de komponenter, vi vil
diskutere er:
- Executor framework
- ExecutorService
- TrådPool
- Kan kaldes
- Låse - ReentrantLock
- Semafor
- ForkJoinPool
Executor Framework I Java
Executor Framework i Java blev frigivet med JDK 5-udgivelsen. Executor Framework (java.util.concurrent.Executor) er en ramme, der består af komponenter, der hjælper os med effektivt at håndtere flere tråde.
Ved hjælp af Executor Framework kan vi køre objekter, der kan køres, ved at genbruge de allerede eksisterende tråde. Vi behøver ikke oprette nye tråde hver gang, når vi har brug for at køre objekter.
Executor API adskiller eller afkobler udførelsen af en opgave fra den aktuelle opgave ved hjælp af en Eksekutor . En eksekutor er centreret på Executor-grænsefladen og har undergrænseflader, dvs. ExecutorService og klassen ThreadPoolExecutor.
Således ved hjælp af Executor er vi bare nødt til at oprette Runnable objekter og derefter sende dem til eksekutoren, der udfører dem.
Nogle af de bedste fremgangsmåder, der skal følges, når du bruger Executor-rammen, er,
- Vi skal krydstjekke og planlægge en kode for at gennemgå de øverste lister, så vi kan opdage dødvande såvel som livelock i koden.
- Java-kode skal altid udføres mod statiske analyseværktøjer. Eksempler af statiske analyseværktøjer er FindBugs og PMD.
- Vi bør ikke kun fange undtagelser, men også fejlene i programmer med flere tråde.
Lad os nu diskutere komponenterne i Executor Framework i Java.
Eksekutor
Eksekutoren kan defineres som en grænseflade, der bruges til at repræsentere et objekt, der udfører de opgaver, der gives til det. Om opgaven skal køres på den aktuelle eller nye tråd afhænger af det punkt, hvor indkaldelsen blev startet, hvilket yderligere afhænger af implementeringen.
Så ved hjælp af Executor kan vi afkoble opgaverne fra den aktuelle opgave og derefter køre dem asynkront.
Imidlertid behøver udførelsen af opgaven ved hjælp af Executor ikke være asynkron. Eksekutører kan også påberåbe sig opgaven med det samme ved hjælp af påkaldstråd.
Nedenfor er et eksempel på et stykke kode for at oprette Executor-forekomst:
public class Invoker implements Executor { @Override public void execute (Runnable r_interface) { r_interface.run(); } }
Når påkalderen er oprettet, som vist ovenfor, kan vi bruge den til at udføre opgaven som følger.
public void execute () { Executor executor = new Invoker (); executor.execute ( () -> { //perform task }); }
Bemærk, at hvis opgaven ikke accepteres af eksekutoren, så kaster den RejectedExecutionException.
ExecutorService
En ExecutorService (java.util.concurrent.ExecutorService) planlægger de indsendte opgaver i henhold til tilgængeligheden af tråde og opretholder også en hukommelseskø. ExecutorService fungerer som en komplet løsning til asynkron behandling af opgaver.
For at bruge ExecutorService i kode opretter vi en Runnable-klasse. ExecutorService vedligeholder en trådpulje og tildeler også opgaverne til trådene. Opgaver kan også stå i kø, hvis tråden ikke er tilgængelig.
Nedenfor er et simpelt eksempel på ExecutorService.
import java.util.concurrent.*; public class Main { public static void main(String() args) { //create ExecutorService instance with 10 threads ExecutorService executor_Service = Executors.newFixedThreadPool(10); //assign the service to Runnable instance executor_Service.execute(new Runnable() { @Override public void run() { //print the message System.out.println('Simple Example of ExecutorService!!!'); } }); //shutdown executorService executor_Service.shutdown(); } }
Produktion
I ovenstående program opretter vi en simpel ExecutorService-forekomst med en trådpul bestående af 10 tråde. Det tildeles derefter den Runnable instans og udføres for at udskrive ovenstående meddelelse. Efter udskrivning af meddelelsen lukkes ExecutorService.
Trådbassin
En trådpulje i Java er en gruppe af arbejdstråde, der kan genbruges mange gange og tildeles job.
En trådpulje indeholder en gruppe af tråde med fast størrelse. Hver tråd trækkes ud af trådpuljen og tildeles en opgave af tjenesteudbyderen. Når det tildelte job er afsluttet, gives tråden til trådpuljen igen.
Trådpulje er fordelagtigt, da vi ikke behøver at oprette en ny tråd hver gang opgaven er tilgængelig, hvorved ydeevnen forbedres. Det bruges i realtidsapplikationer, der bruger Servlet og JSP, hvor trådpuljer bruges til at behandle anmodninger.
I applikationer med flere tråde sparer trådpuljen ressourcer og hjælper med at indeholde paralleliteten inden for foruddefinerede grænser.
Nedenstående Java-program demonstrerer trådpuljen i Java.
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; class WorkerThreadClass implements Runnable { private String message; //thread class constructor public WorkerThreadClass(String s){ this.message=s; } //run method for thread public void run() { System.out.println(' Start: '+message); processmessage(); //sleep between start and end System.out.println(' End: '+ message); } //processmessage method => sleeps the thread for 2 sec private void processmessage() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Main { public static void main(String() args) { //create a ExecutorService instance ExecutorService executor = Executors.newFixedThreadPool(5);//creating a pool of 5 threads //create thread instances and execute them for (int i = 0; i <5; i++) { Runnable workerThrd = new WorkerThreadClass('Thread_' + i); executor.execute(workerThrd);//calling execute method of ExecutorService } //shutdown ExecutorService executor.shutdown(); while (!executor.isTerminated()) { } System.out.println('Finished all threads'); } }
Produktion
I ovenstående programmer er der en trådpulje med 5 tråde, der oprettes ved hjælp af 'newFixedThreadPool' -metoden. Derefter oprettes trådene og føjes til puljen og tildeles ExecutorService til udførelse.
Kan kaldes i Java
Vi ved allerede, at vi kan oprette tråde ved hjælp af to tilgange. En tilgang er ved at udvide trådklassen, mens den anden tilgang er ved at implementere en Runnable-grænseflade.
livscyklusmodel i softwareteknik
Tråde oprettet ved hjælp af Runnable-grænsefladen mangler dog en funktion, dvs. det returnerer ikke et resultat, når tråden afsluttes eller køres () fuldfører udførelsen. Det er her den kaldbare grænseflade kommer ind i billedet.
Ved hjælp af en kaldbar grænseflade definerer vi en opgave, så den returnerer et resultat. Det kan også kaste en undtagelse. Den kaldbare grænseflade er en del af pakken java.util.concurrent.
Den kaldbare grænseflade giver en call () -metode, der er på de samme linjer som run () -metoden, der leveres af den Runnable-interface, med den eneste forskel, at metoden call () returnerer en værdi og kaster den markerede undtagelse.
Opkaldsmetoden () i den kaldbare grænseflade har følgende prototype.
public Object call () throws Exception;
Da call () -metoden returnerer et objekt, skal hovedtråden være opmærksom på dette.
Derfor skal returværdien lagres i et andet objekt, der er kendt for hovedtråden. Dette formål betjenes ved hjælp af et 'fremtidigt' objekt. Et fremtidigt objekt er et objekt, der indeholder resultatet, der returneres af en tråd. Eller med andre ord, det holder resultatet, når Callable vender tilbage.
Callable indkapsler en opgave, der skal køre på en anden tråd. Et fremtidigt objekt gemmer resultatet returneret fra en anden tråd.
En kaldbar grænseflade kan ikke bruges til at oprette en tråd. Vi har brug for Runnable for at oprette en tråd. Derefter kræves et fremtidigt objekt for at gemme resultatet. Java leverer en konkret type med navnet 'FutureTask', der kombinerer funktionaliteten ved at implementere både Runnable og Future.
Vi opretter en FutureTask ved at give en konstruktør Callable. Dette FutureTask-objekt gives derefter til konstruktøren af Thread-klassen for at oprette et Thread-objekt.
Nedenfor er et Java-program, der demonstrerer den kaldbare grænseflade og fremtidige objekt. Vi bruger også FutureTask-objektet i dette program.
Som allerede nævnt opretter vi i programmet en klasse, der implementerer en kaldbar grænseflade med en tilsidesat opkaldsmetode (). I hovedmetoden opretter vi 10 FutureTask-objekter. Hver objektkonstruktør har et kaldbart klasseobjekt som argument. Derefter er FutureTask-objektet knyttet til en trådforekomst.
Derfor opretter vi indirekte en tråd ved hjælp af et kaldbart interface-objekt.
import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; //create a class implementing Callable interface class CallableDemo implements Callable { //define call () method public Object call() throws Exception { Random generator = new Random(); Integer randomNumber = generator.nextInt(10); Thread.sleep(randomNumber * 1000); return randomNumber; } } public class Main { public static void main(String() args) throws Exception { // Array of FutureTask objects FutureTask() randomNumberTasks = new FutureTask(10); for (int i = 0; i <10; i++) { Callable callable = new CallableDemo(); // Create the FutureTask with Callable class randomNumberTasks(i) = new FutureTask(callable); // create thread with FutureTask Thread t = new Thread(randomNumberTasks(i)); //start the thread t.start(); } System.out.println('The contents of FutureTask objects:'); for (int i = 0; i < 10; i++) { // get() contents of FutureTask System.out.print(randomNumberTasks(i).get() + ' '); } } }
Produktion
Som vist i ovenstående program genererer call () -metoden til Callable, der tilsidesættes i klassen, der implementerer Callable, tilfældige tal. Når tråden er startet, viser den disse tilfældige tal.
Vi bruger også FutureTask-objekter i hovedfunktionen. Da det implementerer Future-grænsefladen, behøver vi ikke gemme resultaterne i trådobjekterne. På samme måde kan vi annullere opgaven, kontrollere, om den kører eller er færdig, og også få resultatet ved hjælp af FutureTask-objektet.
ReentrantLock i Java
Vi har diskuteret trådsynkronisering ved hjælp af det synkroniserede nøgleord i detaljer i vores sidste vejledning. Brug af det synkroniserede ord til trådsynkronisering er den grundlæggende metode og er noget stiv.
Ved hjælp af det synkroniserede nøgleord kan en tråd kun låses en gang. Når en tråd forlader den synkroniserede blok, tager den næste tråd også låsen. Der er ingen ventekø. Disse problemer kan forårsage sult i en anden tråd, da det muligvis ikke får adgang til ressourcerne i lang tid.
For at løse disse problemer har vi brug for en fleksibel metode til at synkronisere trådene. “Reentrant Locks” er denne metode i Java, der giver synkronisering med langt større fleksibilitet.
Klassen 'ReentrantLock' implementerer Reentrant-låse og er en del af pakken 'import java.util.concurrent.locks'. ReentrantLock-klassen giver metodesynkronisering for at få adgang til delte ressourcer. Klasser har også låse- og oplåsningsmetoder til låsning / oplåsning af ressourcer, når der er adgang til dem med tråde.
Et særligt træk ved ReentrantLock er, at tråden kan låse den delte ressource mere end én gang ved hjælp af ReentrantLock. Det giver holdoptælling, der er indstillet til en, når tråden låser ressourcen.
Tråden kan genindtaste og få adgang til ressourcen, inden den låses op. Hver gang tråden åbner ressourcen ved hjælp af Reentrant-låsen, øges holdantalet med en. For hver oplåsning mindskes holdtællingen med en.
Når holdantalet når 0, låses den delte ressource op.
ReentrantLock-klassen giver også en retfærdighedsparameter, som er en boolsk værdi, der kan overføres med låsen. Når retfærdighedsparameteren er indstillet til sand, sendes låsen til den længst ventende tråd, når en tråd frigiver låsen. Dette forhindrer sult.
Reentrant-låse kan bruges som følger:
return_type method_name() { reentrantlock.lock(); try { //Do some work } catch(Exception e) { e.printStackTrace(); } finally { reentrantlock.unlock(); } }
Bemærk, at oplåsningssætningen til ReentrantLock altid er i den sidste blok. Dette garanterer, at låsen frigøres, selvom en undtagelse kastes.
Lad os implementere et Java-program for at forstå ReentrantLock.
import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.*; import java.util.concurrent.locks.ReentrantLock; //thread class that implements Runnable interface class ThreadClass implements Runnable { String task_name; //define ReentrantLock object ReentrantLock thrd_lck; //ThreadClass constructor initialized lock and task name public ThreadClass(ReentrantLock r_lock, String t_name) { thrd_lck = r_lock; task_name = t_name; } //thread run () method public void run() { boolean bool_val = false; while (!bool_val) { //check for Outer Lock boolean tryLock_val = thrd_lck.tryLock(); // if lock is free, do the following if(tryLock_val) { try { for(int i=0;i<=6;i++) { if(i>=2) { thrd_lck.lock(); Thread thread_one = new Thread(); System.out.println('Thread Created.....'); if(i==3) { thread_one.setName('Maint Thread2'); System.out.println('Thread Created.....'); } } if(i==4) thrd_lck.unlock(); break; } System.out.println('ReentrantLock=>Is locked after sleep(1500) : ' + thrd_lck.isLocked()); System.out.println('Work done for task : ' + task_name ); bool_val = true; } catch(Exception e) { e.printStackTrace(); } } } } } public class Main { public static void main(String() args) { //define ReentrantLock lock object and service pool ReentrantLock reentrant_lock = new ReentrantLock(); ExecutorService pool = Executors.newFixedThreadPool(2); //create thread instance and pass lock and task name Runnable worker_thread = new ThreadClass(reentrant_lock, 'ThreadJob'); //execute the thread in exec pool pool.execute(worker_thread); //shut down the pool pool.shutdown(); } }
Produktion
I ovenstående program har vi oprettet en tråd og brugt ReentrantLock til den. Ved hjælp af ReentrantLock kan du få adgang til den delte ressource.
Semafor i Java
Den næste metode til trådsynkronisering er ved hjælp af Semaphore. Ved hjælp af denne konstruktion kaldet semafor styres adgangen til en delt ressource via en tæller. Signaler sendes mellem trådene, så vi kan beskytte det kritiske afsnit og også undgå ubesvarede signaler.
En semafor kan defineres som en variabel, der bruges til at styre samtidige processer ved at synkronisere disse processer. Semaforer bruges også til at synkronisere adgang til den delte ressource og derved undgå en race-tilstand. Tilladelsen til en tråd til at få adgang til den delte ressource ved semafor kaldes også en tilladelse.
Afhængigt af hvilke funktioner de udfører, kan semaforer opdeles i to typer:
# 1) Binær semafor: En binær semafor bruges til at synkronisere samtidige processer og implementere gensidig udelukkelse. En binær semafor antager kun to værdier, dvs. 0 og 1.
# 2) Tæller semafor: Tællesemaforen har en værdi, der angiver antallet af processer, der kan komme ind i det kritiske afsnit. Når som helst angiver værdien det maksimale antal processer, der kommer ind i det kritiske afsnit.
Så hvordan fungerer en semafor?
Arbejdet med en semafor kan opsummeres i følgende trin:
- Hvis semafor tæller> 0, betyder det, at tråden har tilladelse til at få adgang til kritisk sektion, og derefter tælles antallet.
- Ellers er tråden blokeret, indtil tilladelsen er erhvervet.
- Når tråden er færdig med adgang til den delte ressource, frigives tilladelsen, og semafortælling øges, så en anden tråd kan gentage ovenstående trin og erhverve tilladelsen.
Ovenstående trin til bearbejdning af semaforer kan opsummeres i nedenstående flowdiagram.
I Java behøver vi ikke implementere vores semafor, men det giver en Semafor klasse, der implementerer semaforefunktionaliteten. Semaphore-klassen er en del af java.util.concurrent pakke.
Semaphore-klassen giver følgende konstruktører, hvor vi kan oprette semaphore-objekt:
spørgsmål til softwaretestinterview for erfarne kandidater
Semaphore (int num_value) Semaphore (int num_value, boolean how)
Her,
num_værdi => startværdi af tilladelsestællingen, der bestemmer antallet af tråde, der kan få adgang til den delte ressource.
hvordan => angiver rækkefølgen, i hvilken trådene får tilladelse (hvordan = sand). Hvis hvordan = falsk, følges ingen sådan ordre.
Nu implementerer vi et Java-program, der demonstrerer Semaphore, der bruges til at styre den delte ressourceadgang og forhindre løbetilstanden.
import java.util.concurrent.*; //class for shared resource class SharedRes { static int count = 0; } class ThreadClass extends Thread { Semaphore sem; String threadName; public ThreadClass(Semaphore sem, String threadName) { super(threadName); this.sem = sem; this.threadName = threadName; } @Override public void run() { // Thread T1 processing if(this.getName().equals('T1')) { System.out.println('Start: ' + threadName); try { System.out.println(threadName + ' :waiting for a permit.'); // acquire the permit sem.acquire(); System.out.println(threadName + ':Acquired permit'); // access shared resource for(int i=0; i <5; i++) { SharedRes.count++; System.out.println(threadName + ': ' + SharedRes.count); Thread.sleep(10); } } catch (InterruptedException exc) { System.out.println(exc); } // Release the permit. System.out.println(threadName + ':Released the permit'); sem.release(); } // Thread T2 processing else { System.out.println('Start: ' + threadName); try { System.out.println(threadName + ':waiting for a permit.'); // acquire the lock sem.acquire(); System.out.println(threadName + ':Acquired permit'); // process the shared resource for(int i=0; i < 5; i++) { SharedRes.count--; System.out.println(threadName + ': ' + SharedRes.count); Thread.sleep(10); } } catch (InterruptedException exc) { System.out.println(exc); } // Release the permit. System.out.println(threadName + ':Released the permit.'); sem.release(); } } } public class Main { public static void main(String args()) throws InterruptedException { //create Semaphore=> #permits = 1 Semaphore sem = new Semaphore(1); // Create thread instances T1 & T2 //T1=> Increments the count; T2=> Decrements the count ThreadClass thread1 = new ThreadClass(sem, 'T1'); ThreadClass thread2 = new ThreadClass(sem, 'T2'); // start T1 & T2 thread1.start(); thread2.start(); // Wait T1 & T2 thread1.join(); thread2.join(); System.out.println('count: ' + SharedRes.count); // display final count. } }
Produktion
Dette program erklærede en klasse for den delte ressource. Det erklærer også en trådklasse, hvor vi har en semaforvariabel, der initialiseres i klassekonstruktøren.
I den overstyrede run () -metode i trådklassen udføres behandling af trådforekomst, hvor tråd erhverver tilladelsen, får adgang til en delt ressource og derefter frigiver tilladelsen.
I hovedmetoden erklærede vi to trådforekomster. Begge tråde startes derefter, og så venter de ved hjælp af tilslutningsmetoden. Endelig vises antallet, dvs. 0, hvilket indikerer, at begge tråde er færdige med den delte ressource.
Gaffel og deltage i Java
Fork / join-rammen blev først introduceret i Java 7. Denne ramme består af værktøjer, der kan fremskynde parallel behandling. Det bruger alle de tilgængelige processorkerner i systemet og fuldfører opgaven. Gaffel / join-rammen bruger divide and conquer tilgangen.
Den grundlæggende idé bag Fork / Join-rammen er, at den første ramme 'Forks', dvs. rekursivt opdeler opgaven i mindre individuelle underopgaver, indtil opgaverne er atomare, så de kan udføres asynkront.
Efter at have gjort dette, ”opgives”, dvs. alle underopgaver sammenføjes rekursivt til en enkelt opgave eller returværdi.
Gaffel / sammenføjningsrammen har en pool af tråde kendt som “ForkJoinPool”. Denne pulje styrer typen 'ForkJoinWorkerThread' af arbejdertråde og giver dermed effektiv parallel behandling.
ForkJoinPool administrerer arbejdertråde og hjælper os også med at få oplysninger om trådpoolens ydeevne og tilstand. ForkJoinPool er en implementering af 'ExecutorService', som vi diskuterede ovenfor.
I modsætning til arbejdertråde opretter ForkJoinPool ikke en separat tråd til hver underopgave. Hver tråd i ForkJoinPool opretholder sin deque (dobbeltkølet) til at gemme opgaver.
Dekken fungerer som trådens balance mellem arbejdsbelastning og gør dette ved hjælp af en 'arbejds stjæling algoritme', der er beskrevet nedenfor.
Arbejd stjæle algoritme
Vi kan definere algoritmen til at stjæle arbejde i enkle ord som 'Hvis en tråd er fri,' stjæler 'værket fra travle tråde'.
En arbejdstråd får altid opgaverne fra dens deque. Når alle opgaver i deken er opbrugt, og deque er tom, vil arbejdertråden tage en opgave fra halen af en anden deque eller fra den 'globale indgangskø'.
På denne måde minimeres muligheden for, at tråde konkurrerer om opgaver, og også antallet af gange, tråden skal spejle efter arbejde, reduceres. Dette skyldes, at tråden allerede har fået det største stykke tilgængeligt arbejde og er færdig med det.
Så hvordan kan vi bruge ForkJoinPool i et program?
Den generelle definition af ForkJoinPool er som følger:
public class ForkJoinPool extends AbstractExecutorService
Klassen ForkJoinPool er en del af pakken “java.util.concurrent”.
I Java 8 opretter vi en forekomst af ForkJoinPool ved hjælp af den statiske metode 'common-pool ()', der giver en reference til den fælles pool eller standardtrådspuljen.
ForkJoinPool commonPool = ForkJoinPool.commonPool ();
I Java 7 opretter vi en ForkJoinPool-forekomst og tildeler den til feltet for hjælpeklasse som vist nedenfor.
public static ForkJoinPool forkJoinPool = new ForkJoinPool(2);
Ovenstående definition indikerer, at puljen har et parallelitetsniveau på 2, således at puljen bruger 2 processorkerner.
For at få adgang til ovenstående pool kan vi give følgende erklæring.
ForkJoinPool forkJoinPool = PoolUtil.forkJoinPool;
Basistypen for ForkJoinPool-opgaver er “ForkJoinTask”. Vi bør udvide en af dens underklasser, dvs. for ugyldige opgaver, RecursiveAction og for opgaver, der returnerer en værdi, RecursiveTask. Begge de udvidede klasser giver en abstrakt metode beregning (), hvor vi definerer opgavens logik.
Nedenfor er et eksempel på at demonstrere ForkJoinPool.
import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; //class declaration for ForkJoinPool tasks class FJPoolTask extends RecursiveAction { private long Load = 0; public FJPoolTask(long Load) { this.Load = Load; } @Override protected void compute() { //if threshold is reached, break tasks into smaller tasks List subtasks = new ArrayList(); subtasks.addAll(createSubtasks()); for(RecursiveAction subtask : subtasks){ subtask.fork(); } } //create subtasks private List createSubtasks() { List sub_tasks =new ArrayList(); FJPoolTask sub_task1 = new FJPoolTask(this.Load / 2); FJPoolTask sub_task2 = new FJPoolTask(this.Load / 2); FJPoolTask sub_task3 = new FJPoolTask(this.Load / 2); sub_tasks.add(sub_task1); sub_tasks.add(sub_task2); sub_tasks.add(sub_task3); return sub_tasks; } } public class Main { public static void main(final String() arguments) throws InterruptedException { //get count of available processors int proc = Runtime.getRuntime().availableProcessors(); System.out.println('Processors available:' +proc); //declare forkJoinPool ForkJoinPool Pool = ForkJoinPool.commonPool(); System.out.println(' Active Threads (Before invoke):' +Pool.getActiveThreadCount()); //Declare ForkJoinPool task object FJPoolTask t = new FJPoolTask(400); //submit the tasks to the pool Pool.invoke(t); System.out.println(' Active Threads (after invoke):' +Pool.getActiveThreadCount()); System.out.println('Common Pool Size :' +Pool.getPoolSize()); } }
Produktion
I ovenstående program finder vi antallet af aktive tråde i systemet før og efter at kalde 'påkalde ()' -metoden. Metoden invoke () bruges til at sende opgaverne til puljen. Vi finder også antallet af tilgængelige processorkerner i systemet.
Ofte stillede spørgsmål
Q # 1) Hvad er Java Util Concurrent?
Svar: Pakken “java.util.concurrent” er et sæt klasser og grænseflader leveret af Java for at lette udviklingen af samtidige (multi-threaded) applikationer. Ved hjælp af denne pakke kan vi direkte bruge grænsefladen og klasser samt API'er uden at skulle skrive vores klasser.
Q # 2) Hvilket af følgende er samtidige implementeringer til stede i java.util. samtidig pakke?
Svar: På et højt niveau indeholder pakken java.util.concurrent hjælpeprogrammer som Executors, Synchronizers, Queues, Timings og Concurrent Collections.
Q # 3) Hvad er fremtidig Java?
Svar: Et fremtidigt objekt (java.util.concurrent.Future) bruges til at gemme resultatet, der returneres af en tråd, når den kaldbare grænseflade implementeres.
port udløser vs. port videresendelse
Spørgsmål nr. 4) Hvad er trådsikker i Java?
Svar: En trådsikker kode eller klasse i Java er en kode eller klasse, der kan deles i et multitrådet eller samtidig miljø uden problemer og giver forventede resultater.
Q # 5) Hvad er den synkroniserede samling i Java?
Svar: En synkroniseret samling er en trådsikker samling. Metoden synkroniseret samling () af klassen java.util.Collections returnerer en synkroniseret (trådsikker) samling.
Konklusion
Med denne vejledning har vi afsluttet emnet multi-threading og samtidighed i Java. Vi har diskuteret multithreading i detaljer i vores tidligere tutorials. Her diskuterede vi samtidigheden og implementeringen relateret til samtidighed og multithreading, der er en del af java.util.concurrent-pakken.
Vi diskuterede yderligere to synkroniseringsmetoder, semaforer og ReentrantLock. Vi diskuterede også ForkJoinPool, der bruges til at udføre opgaverne ved at opdele dem i enklere opgaver og derefter i sidste ende slutte sig til resultatet.
Pakken java.util.concurrent understøtter også Executor-rammen og eksekutorer, der hjælper os med at udføre tråde. Vi diskuterede også implementering af trådpuljer, der består af genanvendelige tråde, der returneres til puljen, når udførelsen er afsluttet.
Vi diskuterede en anden grænseflade svarende til Runnable, som også hjælper os med at returnere et resultat fra tråden og det fremtidige objekt, der bruges til at gemme det opnåede trådresultat.
=> Hold øje med den enkle Java-træningsserie her.
Anbefalet læsning
- Thread.Sleep () - Tråd Sleep () Metode i Java med eksempler
- Java-implementering: Oprettelse og udførelse af Java JAR-fil
- Java Basics: Java Syntax, Java Class og Core Java Concepts
- Java Virtual Machine: Hvordan JVM hjælper med at køre Java-applikationer
- Adgang modifikatorer i Java - vejledning med eksempler
- Java-synkroniseret: Hvad er trådsynkronisering i Java
- JAVA-vejledning til begyndere: 100+ praktiske Java-videovejledninger
- Java-heltal og Java BigInteger-klasse med eksempler