Programmēšana

Mūsdienu vītne: Java vienlaicīguma grunts

Liela daļa no tā, kas jāapgūst par programmēšanu ar Java pavedieniem, nav dramatiski mainījies, salīdzinot ar Java platformas attīstību, taču tas ir mainījies pakāpeniski. Šajā Java pavedienu primerā Kamerons Lairds kā vienlaicīgu programmēšanas tehniku ​​skar dažus no augstākajiem (un zemākajiem) pavedieniem. Iegūstiet pārskatu par to, kas pastāvīgi izaicina daudzlīniju programmēšanu, un uzziniet, kā Java platforma ir attīstījusies, lai risinātu dažas problēmas.

Vienlaicīgums ir viena no lielākajām Java programmu jaunpienācēju raizēm, taču nav pamata ļaut tam jūs biedēt. Pieejama ne tikai lieliska dokumentācija (mēs izpētīsim vairākus avotus šajā rakstā), bet Java pavedieni ir kļuvuši vieglāk strādājami, attīstoties Java platformai. Lai uzzinātu, kā veikt daudzšķiedru programmēšanu Java 6 un 7, jums patiešām ir nepieciešami daži veidojošie elementi. Mēs sāksim ar šiem:

  • Vienkārša vītņota programma
  • Vītņu veidošana ir saistīta ar ātrumu, vai ne?
  • Java vienlaicīguma izaicinājumi
  • Kad lietot Runnable
  • Kad labie pavedieni iet slikti
  • Kas jauns Java 6 un 7
  • Kas notiks ar Java pavedieniem

Šis raksts ir iesācēju aptauja par Java pavedienu paņēmieniem, ieskaitot saites uz dažiem JavaWorld visbiežāk lasītajiem ievada rakstiem par daudzšķiedru programmēšanu. Sāciet savus dzinējus un izpildiet iepriekš norādītās saites, ja esat gatavs sākt mācīties par Java pavedieniem jau šodien.

Vienkārša vītņota programma

Apsveriet šādu Java avotu.

Saraksts 1. FirstThreadingExample

class FirstThreadingExample {public static void main (String [] args) {// Otrais arguments ir aizkave starp // secīgiem rezultātiem. Kavēšanās // tiek mērīta milisekundēs. "10", piemēram, //, nozīmē "drukāt līniju ik pēc // sekundes simtdaļas". ExampleThread mt = jauns ExampleThread ("A", 31); ExampleThread mt2 = jauns ExampleThread ("B", 25); ExampleThread mt3 = jauns ExampleThread ("C", 10); mt.start (); mt2.start (); mt3.start (); }} klase ExampleThread pagarina pavedienu {private int delay; public ExampleThread (String label, int d) {// Piešķiriet šim konkrētajam pavedienam // nosaukumu: "thread" LABEL '". super ("pavediens" "+ etiķete +" ""); kavēšanās = d; } public void run () {for (int skaits = 1, rinda = 1; rinda <20; rinda ++, skaits ++) {mēģiniet {System.out.format ("#%. rindiņa no% s \ n", skaits, getName ()); Thread.currentThread (). Miegs (kavēšanās); } catch (InterruptedException ie) {// Tas būtu pārsteigums. }}}}

Tagad apkopojiet un palaidiet šo avotu tāpat kā jebkuru citu Java komandrindas lietojumprogrammu. Jūs redzēsiet izvadi, kas izskatās apmēram šādi:

Uzskaitījums 2. Vītņotas programmas iznākums

1. līnija no pavediena “A” 1. līnija no pavediena “C” 1. līnija no pavediena “B” 2. līnija no pavediena “C” 3. līnija no pavediena “C” 2. līnija no pavediena “C” 2. līnija no pavediena “B” rinda # 4 no vītnes 'C' ... Līnija # 17 no vītnes 'B' Līnija # 14 no vītnes 'A' Līnija # 18 no vītnes 'B' Līnija # 18 no vītnes 'A' Līnija # 15 no vītnes 'A' Līnija Nr. # 16 no vītnes 'A' Līnija # 17 no pavediena 'A' Līnija # 18 no pavediena 'A' Līnija # 19 no pavediena 'A'

Tas tā - jūs esat Java Vītne programmētājs!

Nu, labi, varbūt ne tik ātri. Lai arī cik maza ir programma sarakstā 1, tajā ir daži smalkumi, kas pelna mūsu uzmanību.

Vītnes un nenoteiktība

Tipisks mācību cikls ar programmēšanu sastāv no četriem posmiem: (1) Pētiet jaunu koncepciju; (2) izpildīt izlases programmu; (3) salīdzināt produkciju ar cerībām; un (4) atkārtot līdz abām spēlēm. Tomēr ņemiet vērā, ka es iepriekš teicu izvadi FirstThreadingExample izskatītos "kaut kas līdzīgs" 2. sarakstam. Tātad tas nozīmē, ka jūsu izvade rindu pa rindai varētu atšķirties no manējās. Kas to par?

Visvienkāršākajās Java programmās ir izpildes kārtības garantija: pirmā rinda galvenais () vispirms tiks izpildīts, pēc tam nākamais un tā tālāk, atbilstoši izsekojot un izslēdzot citas metodes. Vītne vājina šo garantiju.

Vītņu izveide dod jaunu spēku Java programmēšanā; jūs varat sasniegt rezultātus ar pavedieniem, kurus bez tiem nevarētu iztikt. Bet šī vara nāk par cenu apņēmība. Visvienkāršākajās Java programmās ir izpildes kārtības garantija: pirmā rinda galvenais () vispirms tiks izpildīts, pēc tam nākamais un tā tālāk, atbilstoši izsekojot un izslēdzot citas metodes. Vītne vājina šo garantiju. Daudzlīniju programmā "17. līnija no vītnes B"var parādīties ekrānā pirms vai pēc"14. līnija no A pavediena, "un secība pēc vienas un tās pašas programmas izpildes var atšķirties pat tajā pašā datorā.

Nenoteiktība var būt sveša, taču tai nav jābūt satraucošai. Izpildes kārtība ietvaros pavediens paliek paredzams, un ir arī priekšrocības, kas saistītas ar nenoteiktību. Iespējams, esat pieredzējis kaut ko līdzīgu, strādājot ar grafiskām lietotāja saskarnēm (GUI). Piemēri ir notikumu klausītāji Swing vai notikumu apstrādātāji HTML formātā.

Lai gan pilnīga diskusija par pavedienu sinhronizāciju ir ārpus šī ievada darbības jomas, ir viegli izskaidrot pamatus.

Piemēram, ņemiet vērā HTML specifikācijas mehāniku ... onclick = "myFunction ();" ... lai noteiktu darbību, kas notiks pēc lietotāja noklikšķināšanas. Šis pazīstamais nenoteiktības gadījums ilustrē dažas tā priekšrocības. Šajā gadījumā, myFunction () netiek izpildīts noteiktā laikā attiecībā pret citiem avota koda elementiem, bet attiecībā uz galalietotāja darbību. Tātad nenoteiktība nav tikai sistēmas vājums; tas ir arī bagātināšana izpildes modeļa, kas dod programmētājam jaunas iespējas noteikt secību un atkarību.

Izpildes aizkavēšanās un pavedienu apakšklase

Jūs varat mācīties no FirstThreadingExample eksperimentējot ar to patstāvīgi. Mēģiniet pievienot vai noņemt PiemērsVītnes - tas ir, piemēram, konstruktoru piesaukšana ... jauns ExampleThread (etiķete, aizkave); - un lāpīšana ar kavēšanāss. Pamatideja ir tāda, ka programma sākas trīs atsevišķi Vītnes, kas pēc tam darbojas neatkarīgi līdz pabeigšanai. Lai padarītu to izpildi pamācošāku, katrs nedaudz kavējas starp secīgajām rindām, ko tas raksta izvadīšanai; tas dod pārējiem pavedieniem iespēju rakstīt viņu izeja.

Pieraksti to Vītnebāzes programmēšana parasti neprasa rīkoties ar Pārtraukts izņēmums. Tas, kas parādīts FirstThreadingExample ir saistīts ar Gulēt(), nevis ir tieši saistīts ar Vītne. Lielākā daļa Vītneavots neietver a Gulēt(); mērķis Gulēt() šeit ir vienkāršā veidā jāmodelē “savvaļā” atrastu ilgstošu metožu uzvedība.

Kaut kas cits, ko pamanīt 1. sarakstā, ir tas Vītne ir abstrakts klase, kas paredzēta apakšklasei. Tās noklusējums palaist () metode neko nedara, tāpēc apakšklases definīcijā tā ir jāpārņem, lai paveiktu kaut ko noderīgu.

Tas viss attiecas uz ātrumu, vai ne?

Tāpēc tagad jūs varat redzēt mazliet to, kas padara programmēšanu ar pavedieniem sarežģītu. Bet galvenais punkts visu šo grūtību pārvarēšanai nav lai iegūtu ātrumu.

Vairāku pavedienu programmas ne, parasti, pabeigt ātrāk nekā ar vienu vītni - faktiski patoloģiskos gadījumos tie var būt ievērojami lēnāki. Vairāku pavedienu programmu galvenā pievienotā vērtība ir atsaucība. Ja JVM ir pieejami vairāki apstrādes kodoli vai ja programma pavada daudz laika, gaidot vairākus ārējos resursus, piemēram, tīkla atbildes, daudzsavienošana var palīdzēt programmai ātrāk pabeigt.

Padomājiet par GUI lietojumprogrammu: ja tā joprojām reaģē uz galalietotāju punktiem un klikšķiem, meklējot "fonā" atbilstošu pirkstu nospiedumu vai pārrēķinot nākamā gada tenisa turnīra kalendāru, tad tas tika veidots, ņemot vērā vienlaicīgumu. Tipiska vienlaicīga lietojumprogrammu arhitektūra atpazīst un reaģē uz lietotāja darbībām pavedienā, kas atdalīts no skaitļošanas pavediena, kas piešķirts lielās aizmugures slodzes apstrādei. (Sīkāku šo principu ilustrāciju skatiet sadaļā “Vītņu vītne un notikuma nosūtīšanas vītne”.)

Pēc savas programmēšanas jūs, visticamāk, apsvērsiet iespēju to izmantot Vītnevienā no šiem apstākļiem:

  1. Esošai lietojumprogrammai ir pareiza funkcionalitāte, taču tā dažkārt nereaģē. Šie "bloki" bieži ir saistīti ar ārējiem resursiem, kas nav jūsu kontrolē: laikietilpīgi datu bāzes vaicājumi, sarežģīti aprēķini, multivides atskaņošana vai tīkla atbildes ar nekontrolējamu latentumu.
  2. Skaitļošanas ziņā intensīva lietojumprogramma varētu labāk izmantot daudzkodolu resursdatorus. Tas varētu būt gadījums, kad kāds renderē sarežģītu grafiku vai simulē iesaistīto zinātnisko modeli.
  3. Vītne dabiski izsaka lietojumprogrammas nepieciešamo programmēšanas modeli. Pieņemsim, ka, piemēram, jūs modelējat sastrēgumstundu automašīnu vadītāju vai bišu stropā uzvedību. Lai katru vadītāju vai bišu ieviestu kā a Vītnesaistīts objekts varētu būt ērts no programmēšanas viedokļa, izņemot jebkādus ātruma vai atsaucības apsvērumus.

Java vienlaicīguma izaicinājumi

Pieredzējušais programmētājs Neds Batchelder nesen quipped

Daži cilvēki, saskaroties ar problēmu, domā: "Es zinu, es izmantošu pavedienus", un pēc tam divus viņi erpoblēma.

Tas ir smieklīgi, jo tas tik labi modelē problēmu ar vienlaicīgumu. Kā jau minēju, vītņotās programmas, visticamāk, sniegs atšķirīgus rezultātus precīzas pavedienu izpildes secības vai laika ziņā. Tas apgrūtina programmētājus, kuri ir apmācīti domāt par reproducējamiem rezultātiem, stingru apņēmību un nemainīgu secību.

Tas pasliktinās. Dažādi pavedieni var ne tikai radīt rezultātus dažādās secībās, bet arī var apgalvo būtiskākos rezultātu līmeņos. Jaunpienācējam ir viegli daudzskaņoties aizvērt () faila rokturis vienā Vītne pirms cita Vītne ir pabeidzis visu, kas nepieciešams rakstīšanai.

Vienlaicīgu programmu pārbaude

Pirms desmit gadiem vietnē JavaWorld Deivs Dejers atzīmēja, ka Java valodai ir viena iezīme, kas tik ļoti "tiek plaši izmantota nepareizi", ka viņš to vērtē kā nopietnu dizaina kļūdu. Šī funkcija bija daudzšķiedru.

Dyer komentārs uzsver izaicinājumu pārbaudīt daudzlīniju programmas. Kad jūs vairs nevarat viegli norādīt programmas izvadi noteiktā rakstzīmju secībā, tas ietekmēs to, cik efektīvi varat pārbaudīt vītņoto kodu.

Pareizo sākumpunktu vienlaicīgas programmēšanas iekšējo grūtību risināšanai Heins Kabucs savā Java speciālista biļetenā ir labi teicis: atzīstiet, ka vienlaicīgums ir tēma, kuru jums vajadzētu saprast, un sistemātiski to izpētiet. Protams, ir tādi rīki kā diagrammu veidošanas paņēmieni un oficiālās valodas, kas palīdzēs. Bet pirmais solis ir saasināt intuīciju, praktizējot ar tādām vienkāršām programmām kā FirstThreadingExample sarakstā 1. Pēc tam uzziniet pēc iespējas vairāk par šādiem pamatprincipiem:

  • Sinhronizācija un nemaināmi objekti
  • Vītņu plānošana un gaidīšana / paziņošana
  • Sacensību apstākļi un strupceļš
  • Vītņu monitori, lai iegūtu ekskluzīvu piekļuvi, nosacījumus un apgalvojumus
  • JUnit paraugprakse - vairāku pavedienu koda pārbaude

Kad lietot Runnable

Objekta orientācija Java definē atsevišķi pārmantotās klases, kam ir sekas daudzlīniju kodēšanai. Līdz šim esmu aprakstījis tikai lietojumu Vītne kas balstījās uz apakšklasēm ar ignorētu palaist (). Objekta dizainā, kas jau bija saistīts ar mantojumu, tas vienkārši nedarbosies. Jūs nevarat vienlaikus mantot no RenderedObject vai Ražošanas līnija vai MessageQueue līdzās Vītne!

Šis ierobežojums ietekmē daudzas Java jomas, ne tikai daudzsavienojumu. Par laimi, ir klasisks problēmas risinājums Skrienams interfeiss. Kā paskaidroja Džefs Frīzens savā 2002. Gada ievadā par vītņošanu, Skrienams interfeiss ir paredzēts situācijām, kad apakšklases Vītne nav iespējams:

The Skrienams interfeiss deklarē vienas metodes parakstu: void run ();. Šis paraksts ir identisks Vītne's palaist () metodes paraksts un kalpo kā pavediena izpildes ieraksts. Tā kā Skrienams ir saskarne, jebkura klase var ieviest šo saskarni, pievienojot īsteno klauzulu klases galvenei un sniedzot atbilstošu palaist () metodi. Izpildes laikā programmas kods var izveidot objektu vai skrienams, no šīs klases un nododiet skrienamā atsauci uz piemērotu Vītne konstruktors.

Tātad tām klasēm, kuras nevar pagarināt Vītne, jums jāizveido skrienams, lai izmantotu daudzsavienojuma priekšrocības. Semantiski, ja jūs nodarbojaties ar sistēmas līmeņa programmēšanu un jūsu klase ir saistīta ar Vītne, tad jums vajadzētu apakšklasē tieši no Vītne. Bet lielākā daļa lietojuma līmeņa daudzsavienojumu izmanto paļaujas uz kompozīciju un tādējādi definē a Skrienams saderīgs ar lietojumprogrammas klases diagrammu. Par laimi, kodēšana, izmantojot., Prasa tikai papildu rindiņu vai divas Skrienams saskarni, kā parādīts 3. sarakstā.

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