concurrency java semaphore
Acest tutorial va discuta despre componentele pachetului java.util.concurrent, cum ar fi Java Semaphore, Executor Framework, ExecutorService pentru a implementa concurența în Java:
Din tutorialele noastre Java anterioare, știm că platforma Java acceptă programarea simultană de la bază. Unitatea de bază a concurenței este un thread și am discutat în detaliu fire și multi-threading în Java.
De la Java 5, un pachet numit „java.util.concurrent” a fost adăugat la platforma Java. Acest pachet conține un set de clase și biblioteci care face mai ușor pentru programator dezvoltarea de aplicații concurente (multi-threaded). Folosind acest pachet, nu trebuie să scriem clase complexe, deoarece avem implementări gata ale majorității conceptelor concurente.
=> Verificați TOATE Tutorialele Java aici.
În acest tutorial, vom discuta diferitele componente ale pachetului java.util.concurrent referitor la concurență și multithreading în Java.
Ce veți învăța:
declanșarea portului față de redirecționarea porturilor pentru jocuri
Pachetul java.util.concurrent
Mai jos sunt enumerate diferitele componente ale pachetului java.util.concurrent privind concurența și multithreading în Java. Să explorăm fiecare componentă în detaliu cu ajutorul unor exemple simple de programare. Unele dintre componente le vom face
discutăm sunt:
- Cadrul executorului
- ExecutorService
- ThreadPool
- Apelabil
- Locks- ReentrantLock
- Semafor
- ForkJoinPool
Executor Framework În Java
Executor Framework în Java a fost lansat odată cu versiunea JDK 5. Executor Framework (java.util.concurrent.Executor) este un cadru care constă din componente care ne ajută să gestionăm eficient mai multe fire.
Folosind Executor Framework, putem rula obiecte care pot fi rulate prin reutilizarea firelor deja existente. Nu trebuie să creăm fire noi de fiecare dată când trebuie să rulăm obiecte.
API-ul Executor separă sau desparte executarea unei sarcini de sarcina reală folosind un Executor testamentar . Un executant este centrat pe interfața Executor și are subinterfețe adică ExecutorService și clasa ThreadPoolExecutor.
Astfel, folosind Executor, trebuie doar să creăm obiecte Runnable și apoi să le trimitem executorului care le execută.
Unele dintre cele mai bune practici care trebuie urmate în timpul utilizării cadrului Executor sunt:
- Ar trebui să verificăm încrucișat și să planificăm un cod pentru a revizui listele de top, astfel încât să putem detecta impasul, precum și blocajul viu din cod.
- Codul Java trebuie executat întotdeauna împotriva instrumentelor de analiză statică. Exemple dintre instrumentele de analiză statică sunt FindBugs și PMD.
- Nu ar trebui să prindem doar excepții, ci și erorile din programele multi-thread.
Acum să discutăm despre componentele Executor Framework în Java.
Executor testamentar
Executorul poate fi definit ca o interfață utilizată pentru a reprezenta un obiect care execută sarcinile furnizate acestuia. Dacă sarcina trebuie executată pe firul curent sau nou depinde de punctul de unde a fost inițiată invocarea, care depinde în continuare de implementare.
Așadar, folosind Executor, putem decupla sarcinile de sarcina reală și apoi le putem rula asincron.
Cu toate acestea, executarea sarcinii folosind Executor nu trebuie să fie asincronă. Executorii pot invoca, de asemenea, sarcina instantaneu utilizând firul de invocare.
Dat mai jos este un exemplu de cod pentru a crea instanța Executor:
public class Invoker implements Executor { @Override public void execute (Runnable r_interface) { r_interface.run(); } }Odată creat invocatorul, așa cum se arată mai sus, îl putem folosi pentru a executa sarcina după cum urmează.
public void execute () { Executor executor = new Invoker (); executor.execute ( () -> { //perform task }); }Rețineți că, dacă sarcina nu este acceptată de Executor, atunci aruncă RejectedExecutionException.
ExecutorService
Un ExecutorService (java.util.concurrent.ExecutorService) programează sarcinile trimise conform disponibilității firelor și menține, de asemenea, o coadă de memorie. ExecutorService acționează ca o soluție completă pentru procesarea asincronă a sarcinilor.
Pentru a utiliza ExecutorService în cod, creăm o clasă Runnable. ExecutorService menține un pool de fire și atribuie, de asemenea, sarcinile firelor. Sarcinile se pot face și la coadă în cazul în care firul nu este disponibil.
Dat mai jos este un exemplu simplu de 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(); } } Ieșire

În programul de mai sus, creăm o instanță simplă ExecutorService cu un pool de fire compus din 10 fire. Apoi este atribuit instanței Runnable și executat pentru a imprima mesajul de mai sus. După tipărirea mesajului, ExecutorService este oprit.
Pool de fire
Un pool de fire din Java este un grup de fire de lucru care pot fi refolosite de multe ori și atribuite lucrări.
Un grup de fire conține un grup de fire de dimensiuni fixe. Fiecare fir este extras din grupul de fire și i se atribuie o sarcină de către furnizorul de servicii. Odată ce lucrarea atribuită este finalizată, firul este dat din nou grupului de fire.
Grupul de fire este avantajos, deoarece nu trebuie să creăm un fir nou de fiecare dată când sarcina este disponibilă, astfel performanța este îmbunătățită. Este utilizat în aplicații în timp real care utilizează Servlet și JSP, unde sunt utilizate pool-uri de fire pentru a procesa cererile.
În aplicațiile multi-thread, Thread Pool economisește resurse și ajută la conținerea paralelismului în limite predefinite.
Programul Java de mai jos demonstrează grupul de fire din 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'); } } Ieșire

În programele de mai sus, există un grup de fire de 5 fire care sunt create folosind metoda „newFixedThreadPool”. Apoi firele sunt create și adăugate la pool și atribuite ExecutorService pentru executare.
Apelabil în Java
Știm deja că putem crea fire utilizând două abordări. O abordare este extinderea clasei Thread, în timp ce a doua abordare este implementarea unei interfețe Runnable.
Cu toate acestea, firele create utilizând interfața Runnable nu au o caracteristică, adică nu returnează un rezultat atunci când firul este terminat sau executarea () finalizează execuția. Aici intervine interfața Callable.
Folosind o interfață Callable definim o sarcină astfel încât să returneze un rezultat. De asemenea, poate arunca o excepție. Interfața Callable face parte din pachetul java.util.concurrent.
Interfața Callable oferă o metodă call () care se află pe liniile similare cu metoda run () oferită de interfața Runnable cu singura diferență că metoda call () returnează o valoare și aruncă o excepție verificată.
Metoda call () a interfeței Callable are următorul prototip.
public Object call () throws Exception; Deoarece metoda call () returnează un obiect, firul principal trebuie să fie conștient de acest lucru.
Prin urmare, valoarea returnată trebuie stocată într-un alt obiect cunoscut de firul principal. Acest scop este servit prin utilizarea unui obiect „Viitor”. Un obiect viitor este un obiect care deține rezultatul returnat de un fir. Sau cu alte cuvinte, va reține rezultatul atunci când Callable revine.
Callable încapsulează o sarcină care ar trebui să ruleze pe un alt fir. Un obiect Future stochează rezultatul returnat dintr-un alt fir.
O interfață apelabilă nu poate fi utilizată pentru a crea un fir. Avem nevoie de Runnable pentru a crea un thread. Apoi pentru a stoca rezultatul este necesar un obiect Viitor. Java oferă un tip concret denumit „FutureTask” care combină funcționalitatea prin implementarea atât Runnable cât și Future.
Creăm o FutureTask oferind unui constructor Callable. Acest obiect FutureTask este apoi dat constructorului clasei Thread pentru a crea un obiect Thread.
Mai jos este prezentat un program Java care demonstrează interfața Callable și obiectul Future. De asemenea, folosim obiectul FutureTask în acest program.
După cum sa menționat deja, în program creăm o clasă care implementează o interfață apelabilă cu o metodă de apel suprascris (). În metoda principală, creăm 10 obiecte FutureTask. Fiecare constructor de obiecte are ca obiect un obiect de clasă Callable. Apoi obiectul FutureTask este asociat cu o instanță thread.
Prin urmare, în mod indirect creăm un fir utilizând un obiect de interfață apelabil.
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() + ' '); } } } Ieșire
Întrebări și răspunsuri la interviu cu selenium webdriver pentru o experiență de 3 ani

Așa cum se arată în programul de mai sus, metoda call () a Callable care este suprascrisă în clasa care implementează Callable generează numere aleatorii. Odată ce firul este pornit, acesta afișează aceste numere aleatorii.
De asemenea, folosim obiecte FutureTask în funcția principală. Pe măsură ce implementează interfața Viitor, nu trebuie să stocăm rezultatele în obiectele Thread. În mod similar, putem anula sarcina, putem verifica dacă se execută sau este finalizată și, de asemenea, putem obține rezultatul folosind obiectul FutureTask.
ReentrantLock în Java
Am discutat în detaliu sincronizarea firelor utilizând cuvântul cheie sincronizat în ultimul nostru tutorial. Utilizarea cuvântului sincronizat pentru sincronizarea firelor este metoda de bază și este oarecum rigidă.
Folosind cuvântul cheie sincronizat, un fir se poate bloca o singură dată. De asemenea, după ce un fir iese din blocul sincronizat, următorul fir preia blocarea. Nu există coadă de așteptare. Aceste probleme pot cauza înfometarea altor fire, deoarece este posibil să nu aibă acces la resurse pentru o lungă perioadă de timp.
Pentru a rezolva aceste probleme, avem nevoie de o metodă flexibilă de sincronizare a firelor. „Blocări de reîntroducere” este această metodă în Java care oferă sincronizare cu o flexibilitate mult mai mare.
Clasa „ReentrantLock” implementează blocaje Reentrant și face parte din pachetul „import java.util.concurrent.locks”. Clasa ReentrantLock oferă sincronizarea metodei pentru a accesa resursele partajate. Clasele au, de asemenea, metode de blocare și deblocare pentru blocarea / deblocarea resurselor atunci când sunt accesate de fire.
O caracteristică particulară a ReentrantLock este că firul poate bloca resursa partajată de mai multe ori utilizând ReentrantLock. Oferă numărul de așteptări care este setat la unu când firul blochează resursa.
Firul poate reintroduce și accesa resursa înainte de deblocare. De fiecare dată când firul accesează resursa utilizând blocarea Reentrant, numărul de așteptări este incrementat cu unul. Pentru fiecare deblocare, numărul de așteptări este scăzut cu unul.
Când numărul de așteptări ajunge la 0, resursa partajată este deblocată.
Clasa ReentrantLock oferă, de asemenea, un parametru de corectitudine, care este o valoare booleană care poate fi transmisă cu constructorul blocării. Când parametrul de corectitudine este setat la adevărat, atunci de fiecare dată când un fir eliberează blocarea, blocarea este trecută la cel mai lung fir de așteptare. Acest lucru previne foametea.
Încuietorile Reentrant pot fi utilizate după cum urmează:
return_type method_name() { reentrantlock.lock(); try { //Do some work } catch(Exception e) { e.printStackTrace(); } finally { reentrantlock.unlock(); } } Rețineți că declarația de deblocare pentru ReentrantLock este întotdeauna în blocul final. Acest lucru garantează că blocarea este eliberată chiar dacă se aruncă o excepție.
Să implementăm un program Java pentru a înțelege 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(); } } Ieșire

În programul de mai sus, am creat un fir și am folosit ReentrantLock pentru acesta. Folosind ReentrantLock, resursa partajată poate fi accesată.
Semafor în Java
Următoarea metodă de sincronizare a firelor este utilizând Semaphore. Folosind acest construct numit semafor, accesul la o resursă partajată este controlat printr-un contor. Semnalele sunt trimise între fire, astfel încât să putem proteja secțiunea critică și, de asemenea, să evităm semnalele ratate.
Un semafor poate fi definit ca o variabilă care este utilizată pentru a gestiona procese simultane prin sincronizarea acestor procese. Semaforele sunt, de asemenea, utilizate pentru a sincroniza accesul la resursa partajată și, astfel, a evita o condiție de rasă. Permisiunea acordată unui thread pentru accesarea resurselor partajate prin semafor se numește și permis.
În funcție de funcțiile pe care le îndeplinesc, semaforele pot fi împărțite în două tipuri:
# 1) Semafor binar: Un semafor binar este utilizat pentru sincronizarea proceselor concurente și implementarea excluderii reciproce. Un semafor binar presupune doar două valori, adică 0 și 1.
# 2) Numărarea semaforului: Semaforul de numărare are o valoare care indică numărul de procese care pot intra în secțiunea critică. În orice moment, valoarea indică numărul maxim de procese care intră în secțiunea critică.
Deci, cum funcționează un semafor?
Funcționarea unui semafor poate fi rezumată în următorii pași:
- Dacă numărul de semafor este> 0, înseamnă că firul are permisiunea de a accesa secțiunea critică, iar apoi numărul este decrementat.
- În caz contrar, firul este blocat până la obținerea permisului.
- Când firul se termină cu accesarea resursei partajate, permisul este eliberat și numărul semaforului este incrementat, astfel încât un alt fir să poată repeta pașii de mai sus și să obțină permisul.
Etapele de mai sus ale lucrării semaforelor pot fi rezumate în diagrama de flux de mai jos.

În Java, nu trebuie să ne implementăm semaforul, dar oferă un Semafor clasă care implementează funcționalitatea semaforului. Clasa Semaphore face parte din java.util.concurrent pachet.
Clasa Semaphore oferă următorii constructori cu ajutorul cărora putem crea obiect semafor:
Semaphore (int num_value) Semaphore (int num_value, boolean how) Aici,
num_value => valoarea inițială a numărului de permise care determină numărul de fire care pot accesa resursa partajată.
cum => setează ordinea în care firele vor fi acordate permise (cum = adevărat). Dacă cum = fals, atunci nu se urmează o astfel de ordine.
Acum vom implementa un program Java care va demonstra semaforul care este utilizat pentru a gestiona accesul la resurse partajate și pentru a preveni starea cursei.
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. } } Ieșire

Acest program a declarat o clasă pentru resursa partajată. De asemenea, declară o clasă de fir în care avem o variabilă de semafor care este inițializată în constructorul clasei.
În metoda suprascrisă run () a clasei Thread, procesarea instanței thread se face în care thread obține permisul, accesează o resursă partajată și apoi eliberează permisul.
În metoda principală, am declarat două instanțe de fir. Ambele fire sunt apoi pornite și apoi așteaptă folosind metoda join. În cele din urmă, numărul este afișat, adică 0, indicând faptul că ambele fire au terminat cu resursa partajată.
cel mai bun instrument gratuit de reparare Windows 7
Furcați și participați la Java
Cadrul fork / join a fost introdus pentru prima dată în Java 7. Acest cadru constă din instrumente care pot accelera procesarea paralelă. Folosește toate nucleele procesorului disponibile în sistem și finalizează sarcina. Cadrul fork / join folosește abordarea divide și cucerește.
Ideea de bază din spatele cadrului Fork / Join este că primul cadru „Forks”, adică rupe recursiv sarcina în subtaskuri individuale mai mici până când sarcinile sunt atomice, astfel încât să poată fi executate asincron.
După ce faceți acest lucru, sarcinile sunt „unite”, adică toate subtaskurile sunt unite recursiv într-o singură sarcină sau o valoare returnată.
Cadrul fork / join are un grup de fire cunoscute sub numele de „ForkJoinPool”. Acest pool gestionează tipul de fire de lucru „ForkJoinWorkerThread”, oferind astfel o procesare paralelă eficientă.
ForkJoinPool gestionează firele de lucru și, de asemenea, ne ajută să obținem informații cu privire la performanța și starea grupului de fire. ForkJoinPool este o implementare a „ExecutorService” pe care am discutat-o mai sus.
Spre deosebire de firele de lucru, ForkJoinPool nu creează un fir separat pentru fiecare subtask. Fiecare fir din ForkJoinPool își menține deque-ul (coada cu două capete) pentru a stoca sarcini.
Deque acționează ca echilibrarea volumului de lucru al firului și face acest lucru cu ajutorul unui „algoritm de furt de lucru”, care este descris mai jos.
Algoritmul de furt de lucru
Putem defini algoritmul de furt de lucru în cuvinte simple ca „Dacă un fir este liber,„ fură ”lucrarea de pe firele ocupate”.
Un fir de lucru va primi întotdeauna sarcinile din deque. Când toate sarcinile din deque sunt epuizate și deque-ul este gol, firul lucrător va prelua o sarcină din coada altui deque sau din „coada de intrare globală”.
În acest fel, posibilitatea ca firele să concureze pentru sarcini este redusă la minimum și, de asemenea, numărul de ori când firul trebuie să caute pentru muncă este redus. Acest lucru se datorează faptului că firul a obținut deja cea mai mare parte din munca disponibilă și a terminat-o.
Deci, cum putem folosi ForkJoinPool într-un program?
Definiția generală a ForkJoinPool este după cum urmează:
public class ForkJoinPool extends AbstractExecutorServiceClasa ForkJoinPool face parte din pachetul „java.util.concurrent”.
În Java 8, creăm o instanță a ForkJoinPool folosind metoda sa statică „common-pool ()” care oferă o referință la pool-ul comun sau la pool-ul implicit de fire.
ForkJoinPool commonPool = ForkJoinPool.commonPool ();În Java 7, creăm o instanță ForkJoinPool și o atribuim câmpului clasei de utilități așa cum se arată mai jos.
public static ForkJoinPool forkJoinPool = new ForkJoinPool(2);Definiția de mai sus indică faptul că pool-ul are un nivel de paralelism de 2, astfel încât pool-ul va utiliza 2 nuclee de procesor.
Pentru a accesa grupul de mai sus, putem da următoarea declarație.
ForkJoinPool forkJoinPool = PoolUtil.forkJoinPool;Tipul de bază pentru sarcinile ForkJoinPool este „ForkJoinTask”. Ar trebui să extindem una dintre subclasele sale, adică pentru sarcinile nule, RecursiveAction și pentru sarcinile care returnează o valoare, RecursiveTask. Ambele clase extinse oferă o metodă abstractă compute () în care definim logica sarcinii.
Dat mai jos este un exemplu pentru a demonstra 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()); } } Ieșire

În programul de mai sus, găsim numărul de fire active din sistem înainte și după apelarea metodei „invoke ()”. Metoda invoke () este utilizată pentru a trimite sarcinile la pool. De asemenea, găsim numărul de nuclee de procesor disponibile în sistem.
întrebări frecvente
Q # 1) Ce este Java Util Concurrent?
Răspuns: Pachetul „java.util.concurrent” este un set de clase și interfețe furnizate de Java pentru a facilita dezvoltarea aplicațiilor concurente (multi-threaded). Folosind acest pachet putem folosi direct interfața și clasele, precum și API-urile fără a fi nevoiți să scriem clasele noastre.
Q # 2) Care dintre următoarele sunt implementări concurente prezente în java.util. pachet concurent?
Răspuns: La un nivel ridicat, pachetul java.util.concurrent conține utilitare precum Executori, sincronizatoare, cozi, temporizări și colecții simultane.
Î. 3) Ce este viitorul Java?
Răspuns: Un obiect Viitor (java.util.concurrent.Future) este utilizat pentru a stoca rezultatul returnat de un fir atunci când este implementată interfața apelabilă.
Q # 4) Ce este thread-safe în Java?
Răspuns: Un cod sau o clasă sigură în Java este un cod sau o clasă care poate fi partajată într-un mediu multi-thread sau simultan fără probleme și produce rezultatele așteptate.
Q # 5) Care este colecția sincronizată în Java?
Răspuns: O colecție sincronizată este o colecție sigură pentru fire. Metoda synchronized collection () a clasei java.util.Collections returnează o colecție sincronizată (thread-safe).
Concluzie
Cu acest tutorial, am finalizat subiectul multi-threading și concurență în Java. Am discutat în detaliu multithreading în tutorialele noastre anterioare. Aici, am discutat despre concurența și implementarea legate de concurență și multithreading care fac parte din pachetul java.util.concurrent.
Am discutat încă două metode de sincronizare, semaforele și ReentrantLock. De asemenea, am discutat despre ForkJoinPool care este utilizat pentru a executa sarcinile împărțindu-le în sarcini mai simple și apoi alăturând în cele din urmă rezultatul.
Pachetul java.util.concurrent acceptă, de asemenea, cadrul Executor și executorii care ne ajută să executăm fire. De asemenea, am discutat despre implementarea pool-ului de fire care constă din fire reutilizabile care sunt returnate pool-ului la finalizarea execuției.
Am discutat o altă interfață similară cu Runnable care ne ajută, de asemenea, să returnăm un rezultat din thread și obiectul Future folosit pentru a stoca rezultatul threadului obținut.
=> Urmăriți aici seria de antrenament Java simplă.
Lectură recomandată
- Thread.Sleep () - Metoda Thread Sleep () în Java cu exemple
- Implementarea Java: crearea și executarea fișierului Java JAR
- Noțiuni de bază Java: Sintaxă Java, Java Class și concepte de bază Java
- Mașină virtuală Java: Cum ajută JVM la rularea aplicației Java
- Modificatori de acces în Java - Tutorial cu exemple
- Java sincronizat: Ce este sincronizarea firului în Java
- Tutorial JAVA pentru începători: peste 100 de cursuri video Java practice
- Java Integer și Java BigInteger Class cu exemple