Programarea Multithreaded vă permite să se separe prezentarea și prelucrarea informațiilor cu privire la numărul de procese „ușoare“ (procese ușoare), cu acces total la ambele diferitele metode de obiecte de aplicare și domeniile lor. Multithreading este indispensabilă în cazurile în care GUI ar trebui să răspundă la acțiunile utilizatorului în performanța unei prelucrare a informațiilor specifice. Fire pot interacționa unii cu alții prin intermediul principal „părinte“, fluxul de la care au pornit.
Ca un exemplu, unele flux responsabil pentru furnizarea de informații în interfața, care așteaptă până când celălalt flux, descărcarea unui fișier și afișează simultan o anumită animație sau actualizează bara de progres. În plus, acest flux poate opri descărcarea unui flux de fișier atunci când apăsați „Cancel“.
Creatorii Java au oferit posibilitatea de a crea două fluxuri: punerea în aplicare a (de punere în aplicare), interfața Runnable și extindere (extindere) clasa fir. Extinderea clasei - aceasta este calea de a moșteni metode și variabile ale clasei părinte. În acest caz, puteți moșteni de la un singur părinte clasa fir. Această limitare poate fi depășită într-o implementare Java a interfeței Runnable. care este cel mai comun mod de a crea un fir.
Beneficiile generate pentru procesul de
- fluxurile de proces mult mai ușor, deoarece acestea necesită mai puțin timp și resurse;
- context, comutarea între firele de execuție este mult mai rapid decât între procese;
- Este mult mai ușor de a realiza interacțiunea între firele de execuție decât între procese.
Firul principal
Fiecare aplicație Java are cel puțin un fir de execuție. Fluxul de la care să înceapă programul, numit principalul. După procesul de creare, de regulă, JVM începe executarea fluxului principal la metoda main (). Apoi, după cum este necesar, fire suplimentare pot fi difuzate. Multithreading - două sau mai multe fire care rulează simultan în același program. Un computer cu un procesor single-core poate executa doar un singur fir, împărțind timpul procesorului între procese și fire.
clasa de fir
Clasa fir definește șapte designeri congestionate, un număr mare de metode pentru transmiterea în flux, și trei (priorități de execuție de curgere) constante.
Clasa de fir Constructorilor
- țintă - o instanță a clasei de punere în aplicare a interfeței Runnable;
- nume - numele fluxului generat;
- grup - grupul la care fluxul.
Exemplu de creare a unui flux care intră în grupul implementează interfața Runnable, și are un nume unic:
Grupuri fluxuri care este utilizat atunci când este necesar pentru a gestiona în mod egal mai multe fluxuri. De exemplu, mai multe fluxuri de date pentru a imprima și necesitatea de a întrerupe imprimarea tuturor documentelor din coada de așteptare. În acest caz, este convenabil să se aplice o comandă pentru toate fluxurile în același timp, mai degrabă decât separat pentru fiecare fir. Dar se poate face, în cazul în care fluxurile sunt atribuite unui grup.
În ciuda faptului că firul principal este creat automat, acesta poate fi controlat. Pentru a face acest lucru, trebuie să creați un obiect de clasă de fir prin apelarea currentThread ().
Metode de clasă Subiect
Cele mai frecvent utilizate metode ale clasei fir pentru controlul fluxului:
- getId lung () - obținerea unui identificator flux;
- String getName () - obtinerea numele fluxului;
- int getPriority () - obținerea unui flux de prioritate;
- getState de stat () - determinarea stării de curgere;
- void întrerupere () - execuție de întrerupere a unui fir;
- boolean isAlive () - verifică dacă firul se execută;
- boolean isDaemon () - verificarea dacă «Daemon» curs de apa;
- void JOIN () - de așteptare pentru finalizarea fluxului;
- void JOIN (Millis) - așteptări Millis sfârșitul fluxului de milisecunde;
- void notificare () - «trezire“ flux separat de așteptare «semnal»;
- void notifyAll () - «trezire“ a tuturor firelor de așteptare «semnal»;
- run void () - lansarea unui flux atunci când debitul a fost creat folosind interfața Runnable;
- void setDaemon (bool) - determinarea fluxului sau utilizatorul «Daemonului»;
- void setPriority (int) - determinarea priorității de curgere;
- somn void (int) - debitul de suspensie printr-un interval de timp prestabilit;
- void start () - începe flux.
- void wait () - fluxul de suspensie până când un alt fir de apeluri notifică metoda ();
- void wait (Millis) - debitul suspensiei la Millis milisecunde sau până când un alt fir de apeluri notifică () metoda;
Ciclul de viață al fluxului
Când obiectul fir de program poate fi într-unul din cele patru state principale: „noi“, „muncitor“, „inaplicabil“ și „pasivă“. Atunci când se creează un fir primește de stat „nou» (NEW) și nu vor fi difuzate. Pentru a transfera flux de „nou“ în „viabil» (executabilă) ar trebui să efectueze o metodă de pornire (), determinând metoda run ().
Fluxul poate fi în transferuri unul dintre statele elemente corespunzătoare imbricate Thread.State statice:
NEW - fir este creat, dar nu a început încă;
Runnable - firul se execută;
BLOCAT - debitul este blocat;
AȘTEPTARE - firul este în așteptare pentru sfârșitul operației de un alt fir;
TIMED_WAITING - flux în timp ce așteaptă sfârșitul unui alt fir;
TERMINATED - fluxul este finalizat.
Exemplu de utilizare Subiect
În exemplul considerat ChickenEgg funcționarea în paralel a două fluxuri (ou filet principal și filet), în care există o dispută „care a fost înainte de ou sau de pui?“. Fiecare fir dă avizul său, după o scurtă întârziere, format prin ChickenEgg.getTimeSleep (). Câștigătorul este firul care a vorbit ultimul cuvânt.
Când executați programul următorul mesaj a fost afișat în consola.
Este imposibil de prezis cu exactitate care firul se va termina ultima să vorbească. Data viitoare când executați „câștigătorul“ se poate schimba. Acest lucru se datorează așa-numita „executarea de cod asincron.“ Asincronie oferă fire de independență. Sau, cu alte cuvinte, fire paralele sunt independente una de cealaltă, cu excepția cazurilor în care logica de afaceri este determinată în funcție de fluxul de implementare a fondurilor prevăzute pentru această limbă.
interfaţa Runnable
Interfața runnable conține doar o singură metodă run ():
run (), metoda este executată la un debit începe. După determinarea obiectului Runnable este transmis unul dintre constructorii clasei fir.
Exemplu de clasa RunnableExample, implementează interfața Runnable
Când executați programul următorul mesaj a fost afișat în consola.
sincronizare fir, sincronizate
În timpul funcționării, fluxul de aplicații folosesc adesea resurse partajate definite în afara fluxului. În cazul în care mai multe fire în același timp, începe să facă modificări la resursa partajată, rezultatele programului poate fi imprevizibil. Luați în considerare următorul exemplu:
Exemplul definește o resursă partajată în clasa formă CommonObject în care există câmpul întreg contor. Această resursă utilizează clasa internă. crearea flux CounterThread pentru a mări o valoare contor de un singur ciclu. La începutul câmpului la curgere este setat la 1. După valoarea debitului res.counter finalizare trebuie să fie egal cu 4.
In principal programul de clasa SynchronizedThread.main rula cinci fire. Adică, fiecare fir în ciclul trebuie să crească valoarea res.counter cu unul la patru; și așa mai departe de cinci ori. Dar rezultatul programului pe care este afișat în consola va fi diferit:
Adică, cu un total de resurse res.counter toate lucrările de stream-uri simultan, schimbând alternativ valoarea.
Pentru a evita această situație, trebuie să sincronizați fluxurile. O modalitate de a sincroniza fire asociate cu cuvântul cheie sincronizate. operatorul sincronizat pentru a determina codul de bloc sau metoda, care va fi disponibil doar un singur fir. Puteți utiliza sincronizate în clasele lor sunt definite metode sau blocuri sincronizate. Dar nu pot fi utilizate în variabile sincronizate sau atribute în definiția clasei.
Blocarea la nivel de obiect
Codul de mai jos demonstrează modul de utilizare declarația sincronizate pentru a bloca accesul la obiect.
Blocarea pe metoda și nivelul de clasă
Blocați accesul la resurse pot fi la nivelul metodei și a clasei. Codul de mai jos arată că, în cazul în care există mai multe cazuri de un timp de rulare de clasă DemoClass, doar un singur fir poate efectua demoMethod metoda (), alte fire acces metoda va fi blocat. Acest lucru este necesar atunci când doriți să facă anumite resurse sunt sigure fir.
Fiecare obiect în Java are un monitor asociat, care este un fel de instrument pentru a controla accesul la obiect. Atunci când executarea de cod ajunge declarația sincronizate. obiect monitorul este blocat prin asigurarea unui acces exclusiv la codul de bloc este un singur flux care a produs blocarea. După sfârșitul unui bloc de cod, obiectul monitorului este eliberat și devine disponibil pentru alte fluxuri.
Unele note importante folosesc sincronizate
- Sincronizarea în Java asigură faptul că două fire nu se poate executa o metodă sincronizate în același timp.
- Operatorul poate utiliza numai sincronizat cu metodele și blocuri de cod care poate fi atât static și nu statice.
- Dacă un fir începe să execute metoda Sincronizatã sau bloc, această tehnică / unitate blocată. Când fluxul iese metoda sincronizată sau unitatea JVM deblochează. Blocajul este eliberat, chiar dacă fluxul părăsește metoda sincronizat după finalizarea oricăror erori sau excepții.
- Sincronizarea în Java o NullPointerException este excepția, în cazul în care un obiect este utilizat într-un bloc sincronizat nu este definit, și anume este nul.
- Metodele sincronizate în Java oferă costuri suplimentare pentru performanta aplicatiilor. Prin urmare, ar trebui să utilizați sincronizarea atunci când este absolut necesar.
- În conformitate cu specificația limbii nu poate fi utilizat în constructor sincronizat, deoarece va avea ca rezultat o eroare de compilare.
Interacțiunea dintre fire în Java, așteptați și notifică
Atunci când interacționează fluxuri este adesea necesar să se suspende anumite fluxuri și notificarea ulterioară a realizării unor acțiuni în alte fluxuri. De exemplu, primul flux de acțiune depinde de rezultatul celui de al doilea fluxul de acțiuni, și este necesară într-un fel de a notifica primul flux, al doilea flux de produs / finalizat unele lucrări. metode sunt folosite pentru astfel de situații:
- așteptați () - declanșatoare monitorul și pune firul apelant în starea de așteptare, până când până când un alt fir de apeluri de notificare) metoda (;
- notifica () - continuă fluxul de lucru, care așteptați () metoda a fost numită anterior;
- notifyAll () - CV-urile tuturor fluxurilor care asteapta () metoda a fost numit anterior.
Toate aceste metode sunt numite numai dintr-un context sincronizat (bloc sau metoda sincronizate).
Luați în considerare exemplul „producător-consumator-Warehouse» (producător-Store-Consumer). În timp ce producătorul nu furnizează produsul la depozit, consumatorul nu se poate ridica. Să presupunem că producătorul trebuie să furnizeze 5 unități de un anumit produs. Prin urmare, consumatorul trebuie să obțină toate bunurile. Dar, în același timp, atât în depozitul poate fi nu mai mult de 3 unități de mărfuri. Când puse în aplicare în acest exemplu folosind așteptare () și notifică ().
Clasa Store Listing
Clasa Store conține două metode sincronizate pentru a obține mărfurile obține () și pune mărfurile pentru a adăuga (). La primirea mărfurilor se efectuează de verificare contra COUNT. În cazul în care produsul nu mai este în stoc, adică contra <1, то вызывается метод wait(). который освобождает монитор объекта Store и блокирует выполнение метода get(). пока для этого монитора не будет вызван метод notify() .
Când adăugați bunurile și verifică valoarea stocului la îndemână. În cazul în care stocul este mai mult de 3 unități de mărfuri, livrarea de bunuri se suspendă și solicită să notifice metoda (). care trece de control pentru a obține metoda () pentru a finaliza în timp ce ciclul ().
clase de înregistrări producător și consumator
Producător și consumator clase să pună în aplicare interfața Runnable. run), metoda (au suprascris. Designerii din aceste clase ca un parametru pentru a primi Store de stocare obiect. La începutul de obiecte de date ca fluxuri separate din ciclul numit pus () și a obține () A se păstra clasa pentru „adauga“ si „a primi“ produs.
Listarea Clasa Comerț
În principal clasa de flux Comerț (în metoda principală), obiectele sunt create de producător-Store-Consumer și Start fluxurile de producător și consumator.
Când executați programul următorul mesaj va fi afișat în consola:
Alimentare daemon, daemon
aplicație Java se termină când iese din ultimul fir. Chiar dacă metoda principală () a fost deja finalizată, dar nu au fost încă executate fluxurilor generate de acesta, sistemul va aștepta finalizarea lor.
Totuși, această regulă nu se aplică la fluxul-daemon (Daemon). Dacă ați terminat ultimul flux normal de proces, și au existat doar fire daemon, atunci ei vor fi obligați să pună capăt și executarea cererii se încheie. Cel mai adesea fire Daemon utilizate pentru a îndeplini sarcinile de fond, care deservesc procesul de-a lungul vieții sale.
Declararea unui fir de demon este suficient. Pentru a face acest lucru, înainte de a începe fluxul cauza setDaemon metoda sa (adevărat). Verificați dacă debitul este un demon „th posibil isDaemon metoda de apel (). Ca un exemplu de utilizare daemon-flow-ului poate fi considerată o clasă de comerț, care ar lua forma următoare:
Puteți experimenta cu propria definiție pentru dvs. daemon-flux pentru una din clasele (producători, consumatori) sau ambele clase, și a vedea cum se va comporta sistemul (JVM).
Care punere în aplicare pentru a alege?
De ce avem nevoie de două tipuri de filetare, iar unele dintre ele și când să folosească? Răspunsul este simplu. Punerea în aplicare interfața Runnable este utilizat în cazurile în care clasa moștenește deja o clasă părinte și vă permite să se extindă clasa fir. Pe lângă forma bună de programare Java este considerat a implementa interfata. Acest lucru se datorează faptului că Java poate fi moștenită doar o singură clasă părinte. Astfel, moștenind clasa fir. este imposibil de a moșteni orice altă clasă.
Extinderea clasei fir trebuie utilizată, dacă este necesar, suprascrierea alte metode ale unei clase în afară de metoda run ().
exemple de descărcare
Exemplele de mai sus pe pagina filetarea și sincronizarea firului sub forma proiectului Eclipse poate fi descărcat de aici (14KB).