Programiranje

Sodobni navoji: Java primer za primer

Veliko tega, kar se lahko naučimo o programiranju z nitmi Java, se skozi razvoj platforme Java ni bistveno spremenilo, ampak se je postopoma spreminjalo. V tem priročniku za teme Java Cameron Laird zadeva nekatere visoke (in najnižje) točke niti kot sočasno tehniko programiranja. Pridobite pregled nad tem, kaj je večnitno programiranje večkrat zahtevno, in ugotovite, kako se je platforma Java razvila, da ustreza nekaterim izzivom.

Sočasnost je med največjimi skrbmi novincev v programiranju Java, vendar ni razloga, da bi vas pustila, da vas prestraši. Ne samo, da je na voljo odlična dokumentacija (v tem članku bomo raziskali več virov), ampak so niti Java postale enostavnejše za delo z razvojem platforme Java. Če se želite naučiti programiranja z več nitmi v Javi 6 in 7, potrebujete le nekaj gradnikov. Začeli bomo s tem:

  • Preprost navojni program
  • Pri navojih gre predvsem za hitrost, kajne?
  • Izzivi sočasnosti Java
  • Kdaj uporabiti Runnable
  • Ko se dobre niti pokvarijo
  • Kaj je novega v Java 6 in 7
  • Kaj sledi za niti Java

Ta članek je uvodna raziskava o tehnikah navojev Java, vključno s povezavami do nekaterih najpogosteje prebranih uvodnih člankov JavaWorld o programiranju z več nitmi. Zaženite motorje in sledite zgornjim povezavam, če ste danes pripravljeni začeti spoznavati navoje Java.

Preprost navojni program

Razmislite o naslednjem viru Java.

Seznam 1. FirstThreadingExample

class FirstThreadingExample {public static void main (String [] args) {// Drugi argument je zamuda med // zaporednimi izhodi. Zamuda se // izmeri v milisekundah. "10", na primer //, pomeni, "natisni vrstico vsako // stotinko sekunde". ExampleThread mt = novo ExampleThread ("A", 31); ExampleThread mt2 = novo ExampleThread ("B", 25); ExampleThread mt3 = novo ExampleThread ("C", 10); mt.start (); mt2.start (); mt3.start (); }} class ExampleThread razširja Thread {private int delay; public ExampleThread (Oznaka niza, int d) {// Dajte tej niti // ime: "nit 'LABEL'". super ("nit" "+ nalepka +" ""); zamuda = d; } javni void run () {for (int count = 1, row = 1; row <20; row ++, count ++) {try {System.out.format ("Vrstica #% d iz% s \ n", count, getName ()); Thread.currentThread (). Sleep (delay); } catch (InterruptedException ie) {// To bi bilo presenečenje. }}}}

Zdaj prevedite in zaženite ta vir kot katero koli drugo aplikacijo ukazne vrstice Java. Videli boste izhod, ki je videti nekako takole:

Seznam 2. Izhod navojnega programa

Vrstica # 1 iz niti 'A' Vrstica # 1 iz niti 'C' Vrstica # 1 iz niti 'B' Vrstica # 2 iz niti 'C' Vrstica # 3 iz niti 'C' Vrstica # 2 iz niti 'B' Vrstica # 4 iz niti 'C' ... Vrstica # 17 iz niti 'B' Vrstica # 14 iz niti 'A' Vrstica # 18 iz niti 'B' Vrstica # 15 iz niti 'A' Vrstica # 19 iz niti 'B' # 16 iz niti 'A' Vrstica # 17 iz niti 'A' Vrstica # 18 iz niti 'A' Vrstica # 19 iz niti 'A'

To je to - ti si Java Navoj programer!

No, v redu, mogoče ne tako hitro. Tako majhen, kot je program iz seznama 1, vsebuje nekaj tankočutnosti, ki si zaslužijo našo pozornost.

Niti in nedoločenost

Tipičen učni cikel s programiranjem je sestavljen iz štirih stopenj: (1) preučitev novega koncepta; (2) izvedba vzorčnega programa; (3) primerjajte rezultate s pričakovanji; in (4) ponavljanje do obeh tekem. Upoštevajte pa, da sem prej rekel izhod za FirstThreadingExample bi izgledalo "nekako tako" na seznamu 2. Torej, to pomeni, da se lahko vaš izhod razlikuje od mojega, vrstica za vrstico. Kaj to približno?

V najpreprostejših programih Java obstaja zagotovilo za izvedbo: prva vrstica v glavni () bo izveden najprej, nato naslednji in tako naprej, z ustreznim sledenjem v in iz drugih metod. Navoj oslabi to jamstvo.

Threading prinaša novo moč programiranju Java; rezultate lahko dosežete z nitmi, ki jih brez njih ne bi mogli. Toda to moč ima za ceno odločnost. V najpreprostejših programih Java obstaja zagotovilo za izvedbo: prva vrstica v glavni () bo izvedena najprej, nato naslednja in tako naprej, z ustreznim sledenjem v in iz drugih metod. Navoj oslabi to jamstvo. V večnitnem programu "Vrstica # 17 iz niti B"se lahko prikaže na vašem zaslonu pred ali po"Vrstica # 14 iz niti A, "in vrstni red se lahko razlikuje pri zaporednih izvedbah istega programa, tudi v istem računalniku.

Nedoločenosti morda ni znano, vendar ni nujno, da vas moti. Nalog za izvršbo znotraj nit ostane predvidljiva, z nedoločljivostjo pa obstajajo tudi prednosti. Morda ste imeli kaj podobnega pri delu z grafičnimi uporabniškimi vmesniki (GUI). Primeri so poslušalci dogodkov v Swingu ali vodniki dogodkov v HTML-ju.

Čeprav popolna razprava o sinhronizaciji niti ni v obsegu tega uvoda, je enostavno razložiti osnove.

Upoštevajte na primer mehaniko, kako HTML določa ... onclick = "myFunction ();" ... za določitev dejanja, ki se bo zgodilo po kliku uporabnika. Ta znani primer nedoločenosti ponazarja nekatere njegove prednosti. V tem primeru, myFunction () se ne izvede ob določenem času glede na druge elemente izvorne kode, vendar glede na dejanje končnega uporabnika. Torej nedoločenost ni le šibkost sistema; je tudi obogatitev modela izvedbe, ki daje programerju nove priložnosti za določanje zaporedja in odvisnosti.

Zamude pri izvedbi in podrazvrstitev niti

Lahko se učite od FirstThreadingExample tako da sami eksperimentirate z njim. Poskusite dodati ali odstraniti ExampleThreads - to je priklic konstruktorja, kot je ... nova ExampleThread (oznaka, zamuda); - in igranje z zamudas. Osnovna ideja je, da se program zažene tri ločeno Navojs, ki se nato samostojno izvajajo do zaključka. Da je njihovo izvajanje bolj poučno, se vsak med zaporednimi vrsticami, ki jih zapiše v izhod, nekoliko zakasni; to daje drugim nitkam priložnost za pisanje njihovi izhod.

Upoštevajte to Navojprogramiranje na osnovi na splošno ne zahteva ravnanja z InterruptedException. Tista, prikazana v FirstThreadingExample ima opraviti z spanje (), namesto da bi bili neposredno povezani z Navoj. Večina Navoj-izvirni vir ne vključuje a spanje (); namen spanje () tukaj je na preprost način modelirati vedenje dolgotrajnih metod, ki jih najdemo "v naravi".

V seznamu 1 je treba opaziti še nekaj Navoj je povzetek razred, zasnovan za podrazvrstitev. Privzeto teči () metoda ne naredi ničesar, zato jo je treba v definiciji podrazreda preglasiti, da dosežemo karkoli koristnega.

Tu gre vse za hitrost, kajne?

Zdaj lahko že vidite malo tega, zaradi česar je programiranje z nitmi zapleteno. Toda glavna točka prenašanja vseh teh težav ni pridobiti hitrost.

Večnitni programi nena splošno zaključijo hitreje kot enonitni - v bistvu so lahko v patoloških primerih bistveno počasnejši. Temeljna dodana vrednost večnitnih programov je odzivnost. Če je JVM na voljo več procesorskih jeder ali ko program porabi veliko časa za čakanje na več zunanjih virov, kot so omrežni odzivi, lahko večnitnost pomaga programu hitreje dokončati.

Omislite si aplikacijo GUI: če se še vedno odziva na točke končnega uporabnika in klikne med iskanjem "v ozadju" ustreznega prstnega odtisa ali ponovnim izračunom koledarja za teniški turnir naslednje leto, potem je bila zgrajena z mislijo na sočasnost. Tipična arhitektura sočasne aplikacije postavlja prepoznavanje in odziv na uporabniška dejanja v nit, ločeno od računske niti, dodeljene za obdelavo velikega zalednega bremena. (Za nadaljnjo ponazoritev teh načel glejte "Navojni navoj in nit za pošiljanje dogodkov".)

V svojem programiranju boste najverjetneje razmislili o uporabi Navojv eni od teh okoliščin:

  1. Obstoječa aplikacija ima pravilno funkcionalnost, vendar se včasih ne odziva. Ti "bloki" so pogosto povezani z zunanjimi viri, ki so zunaj vašega nadzora: zamudne poizvedbe v zbirki podatkov, zapleteni izračuni, predvajanje večpredstavnosti ali mrežni odzivi z nenadzorovano zakasnitvijo.
  2. Računalniško intenzivna aplikacija bi lahko bolje izkoristila večjedrne gostitelje. To lahko velja za nekoga, ki upodablja zapletene grafike ali simulira vključeni znanstveni model.
  3. Navoj naravno izraža zahtevani programski model aplikacije. Recimo, da ste na primer modelirali vedenje voznikov avtomobilov v času prometnih konic ali čebel v panju. Za izvedbo vsakega voznika ali čebele kot a Navoj-Povezani objekt je lahko priročen s programskega vidika, ne glede na hitrost ali odzivnost.

Izzivi sočasnosti Java

Izkušeni programer Ned Batchelder je pred kratkim zasmehoval

Nekateri ljudje, ko se soočijo s težavo, pomislijo: "Vem, uporabil bom niti", nato pa imajo dva problema.

To je smešno, ker tako dobro modelira težavo s sočasnostjo. Kot sem že omenil, bodo večnitni programi verjetno dali različne rezultate glede natančnega zaporedja ali časa izvajanja niti. To je zaskrbljujoče za programerje, ki so usposobljeni razmišljati v smislu ponovljivih rezultatov, stroge odločnosti in nespremenljivega zaporedja.

Vse slabše je. Različne niti lahko ne samo dajejo rezultate v različnih naročilih, ampak lahko tudi trditi na bolj pomembnih ravneh za rezultate. Novincu je enostavno večnitnost zapri () datotečni ročaj v enem Navoj pred drugačnim Navoj je končal vse, kar potrebuje za pisanje.

Testiranje sočasnih programov

Pred desetimi leti je na Javu Dave Dyer opozoril, da ima jezik Java eno tako zelo razširjeno napačno funkcijo, da jo je označil za resno oblikovalsko napako. Ta funkcija je bila večnitna.

Dyerjev komentar poudarja izziv testiranja večnitnih programov. Ko izhoda programa ne morete več enostavno določiti z določenim zaporedjem znakov, bo vplivalo na to, kako učinkovito lahko preizkusite svojo navojno kodo.

Pravilno izhodišče za reševanje notranjih težav sočasnega programiranja je v svojih glasilih Java Specialist dobro navedel Heinz Kabutz: prepoznajte, da je sočasnost tema, ki bi jo morali razumeti, in jo sistematično preučujte. V pomoč so seveda orodja, kot so tehnike diagramiranja in formalni jeziki. Toda prvi korak je izostriti svojo intuicijo z vadbo s preprostimi programi, kot je FirstThreadingExample v seznamu 1. Nato se naučite čim več o osnovah navojev, kot so te:

  • Sinhronizacija in nespremenljivi predmeti
  • Načrtovanje niti in počakajte / obvesti
  • Dirkalni pogoji in zastoj
  • Nadzorniki niti za ekskluziven dostop, pogoje in trditve
  • Najboljše prakse JUnit - testiranje večnitne kode

Kdaj uporabiti Runnable

Objektna usmerjenost v Javi definira posamezno podedovane razrede, kar ima posledice za večnitno kodiranje. Do tega trenutka sem opisal samo uporabo za Navoj ki je temeljil na podrazredih z razveljavljenimi teči (). Pri objektni zasnovi, ki je že vključevala dedovanje, to preprosto ne bi delovalo. Ne morete istočasno podedovati od RenderedObject ali Proizvodna linija ali MessageQueue poleg Navoj!

Ta omejitev vpliva na številna področja Jave, ne le na večnitnost. Na srečo obstaja klasična rešitev problema v obliki Teče vmesnik. Kot je pojasnil Jeff Friesen v svojem uvodu v navoje z nitmi leta 2002, Teče vmesnik je narejen za primere, ko je podrazvrstitev Navoj ni mogoče:

The Teče vmesnik razglasi podpis ene same metode: void run ();. Ta podpis je enak Navojje teči () podpis metode in služi kot vnos izvedbe niti. Ker Teče je vmesnik, ga lahko kateri koli razred implementira tako, da pritrdi izvaja klavzuli v glavo razreda in z zagotavljanjem ustreznega teči () metoda. V času izvajanja lahko programska koda ustvari objekt ali vodljiv, iz tega razreda in posredujte referenco runnable ustreznemu Navoj konstruktor.

Torej za tiste razrede, ki se ne morejo razširiti Navoj, morate ustvariti zagon, da izkoristite večnitnost. Semantično, če se ukvarjate s programiranjem na sistemski ravni in je vaš razred v razmerju is-a Navoj, potem bi morali razvrstiti neposredno iz Navoj. Toda večina uporabe večnitnosti na ravni aplikacije se opira na sestavo in tako opredeli a Teče združljiv z diagramom razredov aplikacije. Na srečo potrebujete le dodatno vrstico ali dve za kodiranje z uporabo Teče vmesnik, kot je prikazano v spodnjem seznamu 3.

$config[zx-auto] not found$config[zx-overlay] not found