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:
Useiden ketjujen tuki on rakennettu Java-kielelle ja API: lle
- 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
, g
ja 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, int
s r
, g
ja b
, ovat yksityisiä, ainoa tapa, jolla muut luokat ja objektit voivat käyttää tai vaikuttaa näiden muuttujien arvoihin, on RGBVäri
rakentaja ja menetelmät. Rakentajan ja menetelmien suunnittelu takaa, että:
RGBVäri
konstruktori antaa muuttujille aina oikeat alkuarvotMenetelmät
setColor ()
jakääntää ()
suorittaa aina kelvolliset tilamuunnokset näille muuttujille- 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
, g
ja 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.
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:
Lanka | Lausunto | r | g | b | Väri |
ei mitään | esine edustaa vihreää | 0 | 255 | 0 | |
sininen | sininen lanka kutsuu setColor (0, 0, 255) | 0 | 255 | 0 | |
sininen | checkRGBVals (0, 0, 255); | 0 | 255 | 0 | |
sininen | tämä.r = 0; | 0 | 255 | 0 | |
sininen | tämä.g = 0; | 0 | 255 | 0 | |
sininen | sininen ennakoidaan | 0 | 0 | 0 | |
punainen | punainen lanka kutsuu setColor (255, 0, 0) | 0 | 0 | 0 | |
punainen | checkRGBVals (255, 0, 0); | 0 | 0 | 0 | |
punainen | tämä = r = 255; | 0 | 0 | 0 | |
punainen | tämä.g = 0; | 255 | 0 | 0 | |
punainen | tämä.b = 0; | 255 | 0 | 0 | |
punainen | punainen lanka palaa | 255 | 0 | 0 | |
sininen | myöhemmin sininen lanka jatkuu | 255 | 0 | 0 | |
sininen | tämä. b = 255 | 255 | 0 | 0 | |
sininen | sininen lanka palaa | 255 | 0 | 255 | |
ei mitään | esine edustaa magentaa | 255 | 0 | 255 |
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:
Se on väliaikaista: Lopulta sininen lanka aikoo asettaa värin siniseksi.
- 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:
Lanka | Lausunto | r | g | b | Väri |
ei mitään | esine edustaa vihreää | 0 | 255 | 0 | |
sininen | sininen lanka kutsuu setColor (0, 0, 255) | 0 | 255 | 0 | |
sininen | checkRGBVals (0, 0, 255); | 0 | 255 | 0 | |
sininen | tämä.r = 0; | 0 | 255 | 0 | |
sininen | tämä.g = 0; | 0 | 255 | 0 | |
sininen | sininen ennakoidaan | 0 | 0 | 0 | |
punainen | punainen lanka kutsuu getColor () | 0 | 0 | 0 | |
punainen | int [] retVal = uusi int [3]; | 0 | 0 | 0 | |
punainen | retVal [0] = 0; | 0 | 0 | 0 | |
punainen | retVal [1] = 0; | 0 | 0 | 0 | |
punainen | retVal [2] = 0; | 0 | 0 | 0 | |
punainen | paluu retVal; | 0 | 0 | 0 | |
punainen | punainen lanka palauttaa mustan | 0 | 0 | 0 | |
sininen | myöhemmin sininen lanka jatkuu | 0 | 0 | 0 | |
sininen | tämä. b = 255 | 0 | 0 | 0 | |
sininen | sininen lanka palaa | 0 | 0 | 255 | |
ei mitään | esine edustaa sinistä | 0 | 0 | 255 |
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:
- Synkronoi kriittiset kohdat
- Tee siitä muuttumaton
- 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.