Ohjelmointi

Johdanto Java-ketjuihin

Tässä artikkelissa, joka on yksi ensimmäisistä JavaWorldin julkaisemista, kuvataan, miten ketjut toteutetaan Java-ohjelmointikielellä, aloittaen yleiskatsauksesta ketjuista.

Yksinkertaisesti sanottuna, a lanka on ohjelman toteutuspolku. Suurin osa tänään kirjoitetuista ohjelmista toimii yhtenä ketjuna aiheuttaen ongelmia, kun useita tapahtumia tai toimintoja on tapahduttava samanaikaisesti. Sanotaan esimerkiksi, että ohjelma ei pysty piirtämään kuvia lukiessasi näppäilyjä. Ohjelman on kiinnitettävä täysi huomio näppäimistön syötteeseen, jolla ei ole kykyä käsitellä useampaa kuin yhtä tapahtumaa kerrallaan. Ihanteellinen ratkaisu tähän ongelmaan on kahden tai useamman ohjelman osan saumaton suorittaminen samanaikaisesti. Säikeiden avulla voimme tehdä tämän.

Opi Java-ketjuista

Tämä artikkeli on osa JavaWorldin teknistä sisältöarkistoa. Seuraavassa on lisätietoja Java-ketjuista ja samanaikaisuudesta:

Java-ketjujen ymmärtäminen (Java 101 sarja, 2002):

  • Osa 1: Esittely kierteet ja ajettavat
  • Osa 2: Langan synkronointi
  • Osa 3: Langan ajoitus ja odotus / ilmoitus
  • Osa 4: Lankaryhmät ja volatiliteetti

Aiheeseen liittyvät artikkelit

  • Hyperlankainen Java: Java Concurrency -sovellusliittymän käyttö (2006)
  • Paremmat monisäikeisten ohjelmien monitorit (2007)
  • Näyttelijän samanaikaisuuden ymmärtäminen, osa 1 (2009)
  • Riippulangan tunnistus ja käsittely (2011)

Tarkista myös JavaWorld sivukartta ja hakukone.

Monisäikeiset sovellukset tuottavat tehokkaan tehon suorittamalla useita ketjuja samanaikaisesti yhdessä ohjelmassa. Loogisesta näkökulmasta monisäikeinen tarkoittaa, että yhden ohjelman useita rivejä voidaan suorittaa samanaikaisesti, mutta se ei ole sama kuin ohjelman käynnistäminen kahdesti ja sanomalla, että samanaikaisesti suoritetaan useita ohjelmarivejä aika. Tällöin käyttöjärjestelmä käsittelee ohjelmia kahtena erillisenä ja erillisenä prosessina. Unixissa prosessin haaroittaminen luo aliprosessin, jolla on eri osoitetila sekä koodille että tiedoille. Kuitenkin, haarukka() luo käyttöjärjestelmälle paljon yleiskustannuksia, mikä tekee siitä erittäin prosessoria intensiivisen toiminnan. Aloittamalla ketju sen sijaan luodaan tehokas toteutuspolku jakamalla alkuperäisen tietoalueen vanhemmalta. Ajatus data-alueen jakamisesta on erittäin hyödyllinen, mutta tuo esiin joitain huolenaiheita, joista keskustelemme myöhemmin.

Lankojen luominen

Java-luojat ovat suunnitelleet ystävällisesti kaksi tapaa luoda ketjuja: toteuttaa käyttöliittymä ja laajentaa luokkaa. Luokan laajentaminen on tapa, jolla Java perii menetelmät ja muuttujat vanhemmalta luokalta. Tässä tapauksessa voidaan laajentaa tai periä vain yksinhuoltajaluokasta. Tämä Java-rajoitus voidaan voittaa toteuttamalla rajapintoja, mikä on yleisin tapa luoda ketjuja. (Huomaa, että perintö vain sallii luokan suorittamisen säikeenä. Luokan tehtävänä on alkaa() suorittaminen jne.)

Liitännät tarjoavat ohjelmoijille tavan luoda luokan perusta. Niitä käytetään suunnittelemaan vaatimukset joukolle toteutettavia luokkia. Käyttöliittymä määrittää kaiken, ja käyttöliittymän toteuttava luokka tai luokat tekevät kaiken. Eri käyttöliittymää käyttävien luokkaryhmien on noudatettava samoja sääntöjä.

Luokan ja käyttöliittymän välillä on muutama ero. Ensinnäkin rajapinta voi sisältää vain abstrakteja menetelmiä ja / tai staattisia lopullisia muuttujia (vakioita). Toisaalta luokat voivat toteuttaa menetelmiä ja sisältää muuttujia, jotka eivät ole vakioita. Toiseksi rajapinta ei voi toteuttaa mitään menetelmiä. Rajapinnan toteuttavan luokan on toteutettava kaikki kyseisessä rajapinnassa määritellyt menetelmät. Rajapinnalla on kyky laajentua muista rajapinnoista, ja (toisin kuin luokissa) se voi ulottua useista rajapinnoista. Lisäksi rajapintaa ei voida luoda uuden operaattorin kanssa; esimerkiksi, Runnable a = uusi Runnable (); ei ole sallittua.

Ensimmäinen menetelmä langan luomiseksi on yksinkertaisesti laajentaa Lanka luokassa. Tee tämä vain, jos ketjuna suoritettavaa luokkaa ei tarvitse koskaan laajentaa toisesta luokasta. Lanka luokka määritetään paketissa java.lang, joka on tuotava, jotta luokkamme ovat tietoisia sen määritelmästä.

tuo java.lang. *; julkisen luokan laskuri laajentaa säiettä {public void run () {....}}

Yllä oleva esimerkki luo uuden luokan Laskuri joka laajentaa Lanka luokka ja ohittaa Thread.run () menetelmä omaan käyttöönottoonsa. juosta() menetelmä on silloin, kun kaikki Laskuri luokan lanka on valmis. Sama luokka voidaan luoda toteuttamalla Runnable:

tuo java.lang. *; julkisen luokan laskurityökalut Runnable {Thread T; public void run () {....}}

Tässä abstrakti juosta() menetelmä määritetään Runnable-käyttöliittymässä ja sitä toteutetaan. Huomaa, että meillä on esimerkki Lanka luokka muuttujana Laskuri luokassa. Ainoa ero näiden kahden menetelmän välillä on se, että ottamalla Runnable käyttöön, luokan luomisessa on enemmän joustavuutta Laskuri. Edellä olevassa esimerkissä on edelleen mahdollisuus laajentaa Laskuri luokka tarvittaessa. Suurin osa luoduista luokista, jotka on suoritettava ketjuna, toteuttaa Runnable-ohjelman, koska ne todennäköisesti laajentavat muita toimintoja toisesta luokasta.

Älä ajattele, että Runnable-käyttöliittymä tekee todellista työtä, kun ketju suoritetaan. Se on vain luokka, joka on luotu antamaan idean mallin suunnittelusta Lanka luokassa. Itse asiassa se on hyvin pieni ja sisältää vain yhden abstraktin menetelmän. Tässä on määritettävissä oleva Runnable-käyttöliittymä suoraan Java-lähteestä:

paketti java.lang; julkinen käyttöliittymä Runnable {public abstract void run (); }

Se on kaikki mitä Runnable-käyttöliittymässä on. Käyttöliittymä tarjoaa vain suunnitelman, johon luokat tulisi toteuttaa. Runnable-liitännän tapauksessa se pakottaa määrittelemään vain juosta() menetelmä. Siksi suurin osa työstä tehdään Lanka luokassa. Tarkempi osa määritelmän määritelmästä Lanka luokka antaa käsityksen siitä, mitä todella tapahtuu:

public class Säie toteuttaa Runnable {... public void run () {if (target! = null) {target.run (); }} ...}

Edellä olevasta koodinpätkästä on selvää, että Thread-luokka toteuttaa myös Runnable-käyttöliittymän. Lanka.juosta() tarkistaa, ettei kohdeluokka (luokka, joka ajetaan ketjuna) ei ole yhtä suuri kuin nolla, ja suorittaa sitten juosta() kohteen menetelmä. Kun näin tapahtuu, juosta() Kohteen menetelmä toimii omana säikeenä.

Käynnistys ja pysäytys

Koska eri tapoja luoda ketjun ilmentymä ovat nyt ilmeisiä, keskustelemme ketjujen toteutuksesta alkaen käytettävissä olevista tavoista aloittaa ja pysäyttää ne käyttämällä pientä, langan sisältävää applettia mekaniikan havainnollistamiseksi:

CounterThread-esimerkki ja lähdekoodi

Yllä oleva sovelma alkaa laskea 0: sta näyttämällä lähdön sekä näytölle että konsolille. Pika vilkaisu saattaa antaa vaikutelman, että ohjelma alkaa laskea ja näyttää kaikki numerot, mutta näin ei ole. Tarkempi tarkastelu tämän sovelman suorittamisesta paljastaa sen todellisen identiteetin.

Tässä tapauksessa CounterThread luokka pakotettiin toteuttamaan Runnable, koska se laajensi luokan Appletia. Kuten kaikissa sovelmissa, sen sisällä() menetelmä suoritetaan ensin. Sisään sen sisällä(), muuttuja Count alustetaan nollaksi ja uudeksi Lanka luokka on luotu. Ohittamalla Tämä että Lanka konstruktori, uusi ketju tietää suoritettavan objektin. Tässä tapauksessa Tämä on viittaus CounterThread. Kun ketju on luotu, se on aloitettava. Kutsu alkaa() soittaa kohteen juosta() menetelmä, joka on CounterThread.juosta(). Kutsu alkaa() palaa heti ja ketju alkaa suorittaa samaan aikaan. Huomaa, että juosta() menetelmä on ääretön silmukka. Se on ääretön, koska kerran juosta() menetelmä poistuu, säie lopettaa suorituksen. juosta() method lisää muuttujaa Count, lepotilassa 10 millisekuntia ja lähettää pyynnön päivittää sovelman näyttö.

Huomaa, että on tärkeää nukkua jonnekin langassa. Jos ei, ketju kuluttaa prosessorille kaiken prosessorin ajan eikä salli muiden menetelmien, kuten ketjujen, suorittamista. Toinen tapa lopettaa langan suorittaminen on kutsua lopettaa() menetelmä. Tässä esimerkissä lanka pysähtyy, kun hiirtä painetaan, kun kohdistin on sovelmassa. Riippuen tietokoneen nopeudesta, jossa sovelma toimii, kaikkia numeroita ei näytetä, koska kasvu tapahtuu riippumatta sovelman maalauksesta. Sovellusta ei voi päivittää jokaisesta pyynnöstä, joten käyttöjärjestelmä jonottaa pyynnöt ja peräkkäiset päivityspyynnöt tyydytetään yhdellä päivityksellä. Vaikka päivitykset ovat jonossa, laskuria lisätään edelleen, mutta sitä ei näytetä.

Keskeyttäminen ja jatkaminen

Kun säie on pysäytetty, sitä ei voida käynnistää uudelleen alkaa() komento, koska lopettaa() päättää ketjun suorittamisen. Sen sijaan voit keskeyttää langan suorittamisen nukkua() menetelmä. Lanka nukkuu tietyn ajan ja alkaa sitten suorittaa, kun aikaraja on saavutettu. Mutta tämä ei ole ihanteellinen, jos ketju on aloitettava tietyn tapahtuman tapahtuessa. Tässä tapauksessa keskeyttää() - menetelmä sallii ketjun väliaikaisesti lopettaa suorittamisen ja jatkaa() menetelmä sallii keskeytetyn langan käynnistymisen uudelleen. Seuraava sovelma näyttää yllä olevan esimerkin, jota on muokattu sovituksen keskeyttämiseksi ja jatkamiseksi.

julkinen luokka CounterThread2 laajentaa Applet-työkaluja Runnable {Thread t; int Count; boolean suspendoitu; public boolean mouseDown (Tapahtuma e, int x, int y) {if (keskeytetty) t.resume (); muuten t.suspend (); keskeytetty =! keskeytetty; palaa tosi; } ...}

CounterThread2 Esimerkki ja lähdekoodi

Boolen muuttujan seuraamiseksi sovelman nykyisestä tilasta keskeytetty käytetään. Sovelluksen eri tilojen erottaminen on tärkeää, koska jotkut menetelmät tuottavat poikkeuksia, jos niitä kutsutaan väärässä tilassa. Esimerkiksi, jos sovelma on käynnistetty ja pysäytetty, suoritetaan alkaa() menetelmä heittää IllegalThreadStateException poikkeus.