Ohjelmointi

Suunnittelu kierteen turvallisuuteen

Kuusi kuukautta sitten aloitin sarjan artikkeleita luokkien ja esineiden suunnittelusta. Tässä kuussa Suunnittelutekniikat sarakkeessa, jatkan sarjaa tarkastelemalla lankojen turvallisuutta koskevia suunnitteluperiaatteita. Tässä artikkelissa kerrotaan, mikä on langan turvallisuus, miksi tarvitset sitä, milloin tarvitset sitä ja miten sen hankkiminen.

Mikä on langan turvallisuus?

Kierteen turvallisuus tarkoittaa yksinkertaisesti sitä, että kohteen tai luokan kentät säilyttävät aina kelvollisen tilan, kuten muut objektit ja luokat havaitsevat, vaikka niitä käytettäisiin samanaikaisesti useiden säikeiden kanssa.

Yksi ensimmäisistä suuntaviivoista, jotka ehdotin tässä sarakkeessa (katso "Kohteen alustamisen suunnittelu"), on, että sinun tulisi suunnitella luokat siten, että objektit säilyttävät kelvollisen tilan niiden elinaikan alusta loppuun. Jos noudatat tätä neuvoa ja luot objekteja, joiden ilmentymämuuttujat ovat kaikki yksityisiä ja joiden menetelmät tekevät vain tilansiirtymiä kyseisiin ilmentymämuuttujiin, olet hyvässä kunnossa yksisäikeisessä ympäristössä. Mutta saatat joutua vaikeuksiin, kun lisää säikeitä tulee.

Useat säikeet voivat aiheuttaa objektiisi ongelmia, koska objektin tila voi olla väliaikaisesti virheellinen, kun menetelmä on käynnissä. Kun vain yksi ketju käyttää objektin menetelmiä, vain yksi menetelmä kerrallaan suoritetaan koskaan, ja kunkin menetelmän annetaan lopettaa ennen toisen menetelmän käynnistämistä. Siten yksisäikeisessä ympäristössä jokaiselle menetelmälle annetaan mahdollisuus varmistaa, että väliaikaisesti virheellinen tila muutetaan kelvolliseksi ennen menetelmän paluuta.

Kun olet ottanut käyttöön useita ketjuja, JVM voi keskeyttää ketjun suorittamalla yhden menetelmän, kun objektin ilmentymämuuttujat ovat edelleen väliaikaisesti virheellisessä tilassa. JVM voisi sitten antaa toiselle säikeelle mahdollisuuden suorittaa, ja tämä ketju voi kutsua menetelmää samalle objektille. Kaikki ahkera työsi ilmentymämuuttujien yksityistämiseksi ja menetelmien suorittamiseksi vain kelvollisten tilamuunnosten tekeminen ei riitä estämään tätä toista säiettä tarkkailemasta objektia virheellisessä tilassa.

Tällainen objekti ei olisi langattomasti turvallinen, koska monisäikeisessä ympäristössä esine voi vioittua tai sen voidaan havaita olevan virheellinen tila. Lankavarmuusobjekti on sellainen, joka ylläpitää aina kelvollista tilaa, kuten muut luokat ja objektit havaitsevat, jopa monisäikeisessä ympäristössä.

Miksi huolehtia langan turvallisuudesta?

Langan turvallisuutta on ajateltava kahdesta suuresta syystä suunnitellessasi luokkia ja objekteja Javalassa:

  1. Useiden ketjujen tuki on rakennettu Java-kielelle ja API: lle

  2. Kaikilla Java-virtuaalikoneen (JVM) sisäisillä säikeillä on sama kasa ja menetelmäalue

Koska Java on sisäänrakennettu monisäikeisesti, on mahdollista, että mitä tahansa suunnittelemaasi luokkaa voidaan lopulta käyttää samanaikaisesti useissa säikeissä. Sinun ei tarvitse tehdä (ja sinun ei pitäisi) tehdä jokaisesta luokasta, jota suunnittelet, langattomaksi, koska langan turvallisuus ei tule ilmaiseksi. Mutta sinun pitäisi ainakin ajatella langan turvallisuudesta aina, kun suunnittelet Java-luokan. Seuraavassa tässä artikkelissa on keskustelu langan turvallisuuden kustannuksista ja ohjeet siitä, milloin luokista tehdään langattomia.

JVM: n arkkitehtuurin vuoksi sinun on huolehdittava vain ilmentymien ja luokkien muuttujista, kun olet huolissasi langan turvallisuudesta. Koska kaikilla säikeillä on sama kasa ja kaikki esimerkkimuuttujat on tallennettu kasaan, useat ketjut voivat yrittää käyttää saman objektin ilmentymämuuttujia samanaikaisesti. Vastaavasti, koska kaikilla säikeillä on sama menetelmäalue ja menetelmäalueella kaikki luokkimuuttujat tallennetaan, useat säikeet voivat yrittää käyttää samoja luokkamuuttujia samanaikaisesti. Kun päätät tehdä luokan säiettä turvalliseksi, tavoitteesi on taata kyseisessä luokassa ilmoitettujen esimerkkien ja luokan muuttujien eheys - monisäikeisessä ympäristössä.

Sinun ei tarvitse huolehtia paikallisten muuttujien, menetelmäparametrien ja palautusarvojen monisäikeisestä pääsystä, koska nämä muuttujat sijaitsevat Java-pinossa. JVM: ssä jokaiselle säikeelle myönnetään oma Java-pino. Mikään säie ei näe tai käytä paikallisia muuttujia, palautusarvoja tai toiseen ketjuun kuuluvia parametreja.

Kun otetaan huomioon JVM: n rakenne, paikalliset muuttujat, menetelmäparametrit ja palautusarvot ovat luonnostaan ​​"ketjun turvallisia". Mutta esiintymämuuttujat ja luokkamuuttujat ovat vain langattomia, jos suunnittelet luokkaa asianmukaisesti.

RGBColor # 1: Valmiina yhdelle langalle

Esimerkkinä luokasta, joka on ei kierre turvallinen, harkitse RGBVäri luokka, alla. Tämän luokan esiintymät edustavat väriä, joka on tallennettu kolmeen yksityisen esiintymän muuttujaan: r, gja b. Kun otetaan huomioon alla esitetty luokka, an RGBVäri esine aloittaisi elämänsä kelvollisessa tilassa ja kokisi vain kelvollisen tilan siirtymiä elämänsä alusta loppuun - mutta vain yksisäikeisessä ympäristössä.

// Tiedostokierteissä / ex1 / RGBColor.java // Tämän luokan esiintymät eivät ole langattomia. julkinen luokka RGBColor {private int r; yksityinen int g; yksityinen int b; public RGBColor (int r, int g, int b) {checkRGBVals (r, g, b); tämä.r = r; tämä.g = g; tämä.b = b; } public void setColor (int r, int g, int b) {checkRGBVals (r, g, b); tämä.r = r; tämä.g = g; tämä.b = b; } / ** * palauttaa värin kolmen tuuman ryhmässä: R, G ja B * / public int [] getColor () {int [] retVal = new int [3]; retVal [0] = r; retVal [1] = g; retVal [2] = b; paluu retVal; } public void invert () {r = 255 - r; g = 255 - g; b = 255 - b; } private static void checkRGBVals (int r, int g, int b) {if (r 255 || g 255 || b <0 || b> 255) {heitä uusi IllegalArgumentException (); }}} 

Koska kolme esiintymämuuttujaa, ints r, gja b, ovat yksityisiä, ainoa tapa, jolla muut luokat ja objektit voivat käyttää tai vaikuttaa näiden muuttujien arvoihin, on RGBVärirakentaja ja menetelmät. Rakentajan ja menetelmien suunnittelu takaa, että:

  1. RGBVärikonstruktori antaa muuttujille aina oikeat alkuarvot

  2. Menetelmät setColor () ja kääntää () suorittaa aina kelvolliset tilamuunnokset näille muuttujille

  3. Menetelmä getColor () palauttaa aina kelvollisen näkymän näistä muuttujista

Huomaa, että jos huonoja tietoja välitetään rakentajalle tai setColor () menetelmällä, ne täydentävät äkillisesti InvalidArgumentException. checkRGBVals () menetelmä, joka heittää tämän poikkeuksen, itse asiassa määrittää, mitä se tarkoittaa RGBVäri objekti on kelvollinen: kaikkien kolmen muuttujan arvot, r, gja b, on oltava välillä 0 ja 255, mukaan lukien. Lisäksi, jotta näiden muuttujien edustama väri olisi kelvollinen, sen on oltava viimeisin joko konstruktorille tai setColor () - menetelmällä tai kääntää () menetelmä.

Jos vedot yksisäikeisessä ympäristössä setColor () ja ohita sinisellä, RGBVäri objekti on sininen, kun setColor () palaa. Jos sitten vedot getColor () samasta esineestä saat sinisen. Yksisäikeisessä yhteiskunnassa esiintyy tätä RGBVäri luokka ovat hyvin käyttäytyviä.

Heitetään samanaikainen jakoavain töihin

Valitettavasti tämä onnellinen kuva hyvin käyttäytyvistä RGBVäri esine voi muuttua pelottavaksi, kun muut säikeet tulevat kuvaan. Monisäikeisessä ympäristössä RGBVäri Edellä määritellyt luokat ovat alttiita kahdentyyppiselle huonolle käytölle: kirjoitus- / kirjoitusristiriidoille ja luku- / kirjoitusristiriidoille.

Kirjoita / kirjoita ristiriitoja

Kuvittele, että sinulla on kaksi säiettä, yksi lanka nimeltä "punainen" ja toinen "sininen". Molemmat säikeet yrittävät asettaa saman värin RGBVäri esine: Punainen lanka yrittää asettaa värin punaiseksi; sininen lanka yrittää asettaa värin siniseksi.

Molemmat säikeet yrittävät kirjoittaa samanaikaisesti saman objektin ilmentymämuuttujiin. Jos ketjun ajastin limittää nämä kaksi ketjua oikealla tavalla, nämä ketjut häiritsevät vahingossa toisiaan aiheuttaen kirjoitus- / kirjoitusristiriidan. Prosessissa kaksi säiettä vioittavat objektin tilan.

Synkronoimaton RGBVäri sovelma

Seuraava sovelma, nimeltään Synkronoimaton RGBColor, osoittaa yhden tapahtumasarjan, joka voi johtaa korruptoituneeseen RGBVäri esine. Punainen lanka yrittää syyttömästi asettaa värin punaiseksi, kun taas sininen lanka yrittää viattomasti asettaa värin siniseksi. Loppujen lopuksi RGBVäri esine ei edusta punaista eikä sinistä, vaan levoton väri, magenta.

Jostain syystä selaimesi ei anna sinun nähdä näin viileä Java-sovelma.

Voit käydä läpi tapahtumasarjan, joka johtaa vioittuneeseen RGBVäri paina sovelman Vaihe-painiketta. Varmuuskopioi askel painamalla Takaisin-painiketta ja varmuuskopioi alkuun valitsemalla Palauta. Kun menet, appletin alaosassa oleva tekstirivi selittää, mitä tapahtuu jokaisen vaiheen aikana.

Niille teistä, jotka eivät voi käyttää sovelmaa, tässä on taulukko, joka näyttää sovelman osoittaman tapahtumasarjan:

LankaLausuntorgbVäri
ei mitäänesine edustaa vihreää02550 
sininensininen lanka kutsuu setColor (0, 0, 255)02550 
sininencheckRGBVals (0, 0, 255);02550 
sininentämä.r = 0;02550 
sininentämä.g = 0;02550 
sininensininen ennakoidaan000 
punainenpunainen lanka kutsuu setColor (255, 0, 0)000 
punainencheckRGBVals (255, 0, 0);000 
punainentämä = r = 255;000 
punainentämä.g = 0;25500 
punainentämä.b = 0;25500 
punainenpunainen lanka palaa25500 
sininenmyöhemmin sininen lanka jatkuu25500 
sininentämä. b = 25525500 
sininensininen lanka palaa2550255 
ei mitäänesine edustaa magentaa2550255 

Kuten voit nähdä tästä sovelmasta ja taulukosta, RGBVäri on vioittunut, koska säikeiden ajoitin keskeyttää sinisen säikeen olion ollessa väliaikaisesti virheellisessä tilassa. Kun punainen lanka tulee sisään ja maalaa kohteen punaiseksi, sininen lanka on maalattu vain osittain siniseksi. Kun sininen lanka palaa työn loppuun, se vahingoittaa esinettä vahingossa.

Luku- / kirjoitusristiriidat

Eräänlainen väärinkäyttäytyminen, joka saattaa esiintyä monisäikeisessä ympäristössä RGBVäri luokka on luku- / kirjoitusristiriita. Tällainen ristiriita syntyy, kun objektin tila luetaan ja sitä käytetään väliaikaisesti virheellisessä tilassa toisen säikeen keskeneräisen työn vuoksi.

Huomaa esimerkiksi, että sinisen langan suorittamisen aikana setColor () Edellä esitetyn menetelmän mukaan objekti on jossakin vaiheessa väliaikaisesti virheellisessä mustan tilassa. Täällä musta on väliaikaisesti virheellinen tila, koska:

  1. Se on väliaikaista: Lopulta sininen lanka aikoo asettaa värin siniseksi.

  2. Se on virheellinen: Kukaan ei pyytänyt mustaa RGBVäri esine. Sinisen langan on tarkoitus muuttaa vihreä esine siniseksi.

Jos sininen lanka on ennalta asetettu tällä hetkellä, objekti edustaa mustaa lanka, joka kutsuu getColor () samalla esineellä, toinen lanka havaitsisi RGBVäri kohteen arvo on musta.

Tässä on taulukko, joka näyttää tapahtumasarjan, joka voi johtaa juuri tällaiseen luku / kirjoitus-ristiriitaan:

LankaLausuntorgbVäri
ei mitäänesine edustaa vihreää02550 
sininensininen lanka kutsuu setColor (0, 0, 255)02550 
sininencheckRGBVals (0, 0, 255);02550 
sininentämä.r = 0;02550 
sininentämä.g = 0;02550 
sininensininen ennakoidaan000 
punainenpunainen lanka kutsuu getColor ()000 
punainenint [] retVal = uusi int [3];000 
punainenretVal [0] = 0;000 
punainenretVal [1] = 0;000 
punainenretVal [2] = 0;000 
punainenpaluu retVal;000 
punainenpunainen lanka palauttaa mustan000 
sininenmyöhemmin sininen lanka jatkuu000 
sininentämä. b = 255000 
sininensininen lanka palaa00255 
ei mitäänesine edustaa sinistä00255 

Kuten tästä taulukosta voit nähdä, ongelmat alkavat, kun sininen lanka keskeytyy, kun se on vain osittain viimeistellyt kohteen siniseksi. Tässä vaiheessa esine on väliaikaisesti virheellisessä mustan tilassa, juuri sen, mitä punainen lanka näkee, kun se käynnistää getColor () esineeseen.

Kolme tapaa tehdä esineestä lanka-turvallinen

On periaatteessa kolme lähestymistapaa, joita voit tehdä sellaisen kohteen luomiseksi RGBlanka kierre turvallinen:

  1. Synkronoi kriittiset kohdat
  2. Tee siitä muuttumaton
  3. Käytä langattomaa käärettä

Lähestymistapa 1: Kriittisten osien synkronointi

Selkein tapa korjata sellaisten esineiden hallitsematon käyttäytyminen kuin RGBVäri monisäikeisessä yhteydessä on synkronoida objektin kriittiset osat. Esineen kriittiset kohdat ovat niitä menetelmiä tai koodilohkoja menetelmissä, jotka täytyy suorittaa vain yhdellä säikeellä kerrallaan. Toisin sanoen kriittinen osa on menetelmä tai koodilohko, joka on suoritettava atomisesti yhtenä yhtenäisenä jakamattomana operaationa. Käyttämällä Java-tiedostoja synkronoitu avainsanalla, voit taata, että vain yksi ketju kerrallaan suorittaa objektin kriittiset osat.

Jotta voit tehdä tämän lähestymistavan tehdäksesi objektisi ketjun turvalliseksi, sinun on noudatettava kahta vaihetta: sinun on tehtävä kaikki asiaankuuluvat kentät yksityisiksi ja tunnistettava ja synkronoitava kaikki kriittiset kohdat.

Vaihe 1: Tee kentistä yksityisiä

Synkronointi tarkoittaa, että vain yksi ketju kerrallaan voi suorittaa vähän koodia (kriittinen osa). Joten vaikka se onkin kentät haluat koordinoida pääsyn useisiin ketjuihin, Java: n mekanismi siihen koordinoi tosiasiallisesti pääsyn koodi. Tämä tarkoittaa, että vain jos teet tiedot yksityisiksi, voit hallita pääsyä kyseisiin tietoihin hallitsemalla pääsyä tietoja käsittelevään koodiin.

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