JavaRush /Blog Jawa /Random-JV /Ngatur volatilitas
lexmirnov
tingkat
Москва

Ngatur volatilitas

Diterbitake ing grup

Pandhuan kanggo Nggunakake Variabel Volatile

Miturut Brian Goetz 19 Juni 2007 Asli: Ngatur Volatility Variabel volatil ing Jawa bisa diarani "sinkronisasi-cahaya"; Padha mbutuhake kode kurang kanggo nggunakake saka pamblokiran diselarasake, asring mbukak luwih cepet, nanging mung bisa nindakake bagian sekedhik saka apa pamblokiran diselarasake. Artikel iki nyedhiyakake sawetara pola kanggo nggunakake molah malih kanthi efektif-lan sawetara bebaya babagan ngendi ora bisa digunakake. Kunci duwe rong fitur utama: mutual exclusion (mutex) lan visibilitas. Pengecualian bebarengan tegese kunci mung bisa dicekel siji thread sekaligus, lan properti iki bisa digunakake kanggo ngleksanakake protokol kontrol akses kanggo sumber daya sing dienggo bareng supaya mung siji utas sing bakal digunakake ing siji wektu. Visibilitas minangka masalah sing luwih subtle, tujuane kanggo mesthekake yen owah-owahan sing digawe kanggo sumber daya umum sadurunge kunci dirilis bakal katon ing thread sabanjure sing njupuk kunci kasebut. Yen sinkronisasi ora njamin visibilitas, thread bisa nampa nilai stale utawa salah kanggo variabel umum, kang bakal mimpin kanggo sawetara masalah serius.
Variabel volatile
Variabel volatil nduweni sipat visibilitas sing disinkronake, nanging ora nduweni atomisitas. Iki tegese benang bakal kanthi otomatis nggunakake nilai variabel molah malih sing paling anyar. Bisa digunakake kanggo safety thread , nanging ing kasus sing winates banget: sing ora ngenalake hubungan antarane macem-macem variabel utawa antarane nilai variabel saiki lan mbesuk. Mangkono, molah malih piyambak ora cukup kanggo ngleksanakake counter, mutex, utawa kelas sembarang sing bagean immutable digandhengake karo macem-macem variabel (contone, "wiwitan <= pungkasan"). Sampeyan bisa milih kunci molah malih kanggo salah siji saka rong alasan utama: gamblang utawa skalabilitas. Sawetara konstruksi basa luwih gampang ditulis minangka kode program, lan mengko diwaca lan dimangerteni, nalika nggunakake variabel molah malih tinimbang kunci. Kajaba iku, ora kaya kunci, ora bisa mblokir benang lan mulane kurang rentan kanggo masalah skalabilitas. Ing kahanan sing ana luwih akeh maca tinimbang nulis, variabel molah malih bisa menehi keuntungan kinerja liwat kunci.
Kahanan kanggo nggunakake molah malih sing bener
Sampeyan bisa ngganti kunci karo sing molah malih ing sawetara kahanan winates. Supaya thread aman, loro kritéria kudu ketemu:
  1. Apa sing ditulis ing variabel bebas saka nilai saiki.
  2. Variabel ora melu invarian karo variabel liyane.
Cukup, kahanan kasebut tegese nilai sing sah sing bisa ditulis menyang variabel molah malih ora gumantung saka negara liya ing program kasebut, kalebu kahanan variabel saiki. Kahanan pisanan ora kalebu nggunakake variabel molah malih minangka counters aman thread. Senajan increment (x ++) katon kaya operasi siji, iku bener kabeh urutan maca-ngowahi-nulis operasi sing kudu dileksanakake atom, kang molah malih ora nyedhiyani. A operasi bener bakal mbutuhake sing Nilai x tetep padha ing saindhenging operasi, kang ora bisa ngrambah nggunakake molah malih. (Nanging, yen sampeyan bisa mesthekake yen nilai ditulis mung saka siji utas, kondisi pisanan bisa diilangi.) Ing sawetara kahanan, salah siji kondisi pisanan utawa kaloro bakal dilanggar, nggawe variabel molah malih pendekatan kurang umum digunakake kanggo entuk safety thread saka diselarasake. Listing 1 nuduhake kelas non-thread-aman karo sawetara nomer. Isine invarian - wates ngisor tansah kurang saka utawa padha karo ndhuwur. @NotThreadSafe public class NumberRange { private int lower, upper; public int getLower() { return lower; } public int getUpper() { return upper; } public void setLower(int value) { if (value > upper) throw new IllegalArgumentException(...); lower = value; } public void setUpper(int value) { if (value < lower) throw new IllegalArgumentException(...); upper = value; } } Wiwit sawetara variabel negara diwatesi ing cara iki, iku bakal ora cukup kanggo nggawe kothak ngisor lan ndhuwur molah malih kanggo mesthekake kelas punika Utas aman; sinkronisasi isih bakal dibutuhake. Yen ora, cepet utawa mengko sampeyan bakal apes lan loro Utas performing setLower () lan setUpper () karo nilai cecek bisa mimpin sawetara kanggo negara inconsistent. Contone, yen nilai dhisikan (0, 5), thread A nelpon setLower (4), lan ing wektu sing padha thread B nelpon setUpper (3), operasi interleaved iki bakal nyebabake kesalahan, sanajan loro-lorone bakal pass mriksa. sing mestine kanggo nglindhungi invariant. Akibaté, sawetara bakal (4, 3) - nilai salah. Kita kudu nggawe setLower () lan setUpper () atom kanggo sawetara operasi liyane - lan nggawe lapangan volatile ora bakal nindakake.
Pertimbangan Kinerja
Alesan pisanan kanggo nggunakake volatile yaiku kesederhanaan. Ing sawetara kahanan, nggunakake variabel kasebut mung luwih gampang tinimbang nggunakake kunci sing ana gandhengane. Alesan liya yaiku kinerja, kadhangkala molah malih bakal luwih cepet tinimbang kunci. Pancen angel banget kanggo nggawe pratelan sing tepat lan lengkap kaya "X mesthi luwih cepet tinimbang Y," utamane nalika nerangake operasi internal Java Virtual Machine. (Contone, JVM bisa ngeculake kunci kabeh ing sawetara kahanan, dadi angel kanggo ngrembug biaya molah malih versus sinkronisasi kanthi cara abstrak). Nanging, ing paling arsitektur prosesor modern, biaya maca molah malih ora akeh beda saka biaya maca variabel biasa. Biaya nulis molah malih Ngartekno luwih saka nulis variabel biasa amarga pager memori dibutuhake kanggo visibilitas, nanging umume luwih murah tinimbang nyetel kunci.
Pola kanggo panggunaan sing tepat saka molah malih
Akeh ahli konkurensi cenderung ngindhari nggunakake variabel molah malih kabeh amarga luwih angel digunakake kanthi bener tinimbang kunci. Nanging, ana sawetara pola sing ditetepake kanthi apik, yen ditindakake kanthi ati-ati, bisa digunakake kanthi aman ing macem-macem kahanan. Tansah ngormati watesan molah malih - mung nggunakake volatiles sing independen saka tindakan liya ing program, lan iki kudu supaya sampeyan ora njaluk menyang wilayah mbebayani karo pola iki.
Pola #1: Gendéra Status
Mbok menawa panggunaan kanonik variabel sing bisa diowahi minangka gendéra status boolean sing prasaja sing nuduhake yen ana acara siklus urip siji-wektu sing penting, kayata wiwitan rampung utawa panjaluk mati. Akeh aplikasi kalebu mbangun kontrol wangun: "nganti kita siyap mati, terus mlaku" minangka ditampilake ing Listing 2: Iku volatile boolean shutdownRequested; ... public void shutdown() { shutdownRequested = true; } public void doWork() { while (!shutdownRequested) { // do stuff } } kamungkinan sing mati () cara bakal disebut saka nang endi wae njaba daur ulang - ing thread liyane - supaya sinkronisasi dibutuhake kanggo mesthekake shutdown visibilitas variabel benerRequested. (Bisa disebut saka pamireng JMX, pamireng tumindak ing thread acara GUI, liwat RMI, liwat layanan web, etc.). Nanging, daur ulang karo pamblokiran diselarasake bakal luwih rumit tinimbang daur ulang karo flag negara molah malih kaya ing Listing 2. Amarga molah malih nggawe kode nulis luwih gampang lan gendéra negara ora gumantung ing sembarang negara program liyane, iki conto a apik nggunakake molah malih. Karakteristik gendera status kasebut biasane mung ana siji transisi negara; flag shutdownRequested dadi saka palsu kanggo bener, lan banjur program mati. Pola iki bisa ditambahake menyang gendera negara sing bisa ganti bolak-balik, nanging mung yen siklus transisi (saka palsu menyang bener dadi palsu) kedadeyan tanpa intervensi eksternal. Yen ora, sawetara mekanisme transisi atom, kayata variabel atom, dibutuhake.
Pola #2: Penerbitan aman siji-wektu
Kesalahan visibilitas sing bisa ditindakake nalika ora ana sinkronisasi bisa dadi masalah sing luwih angel nalika nulis referensi obyek tinimbang nilai primitif. Tanpa sinkronisasi, sampeyan bisa ndeleng nilai saiki kanggo referensi obyek sing ditulis dening thread liyane lan isih ndeleng nilai negara stale kanggo obyek kasebut. (Ancaman iki ing ROOT saka masalah karo kesuwur pindho mriksa kunci, ngendi referensi obyek diwaca tanpa sinkronisasi, lan sampeyan resiko ndeleng referensi nyata nanging njupuk obyek sebagian dibangun liwat.) Salah siji cara kanggo aman nerbitaké sawijining obyek iku kanggo nggawe referensi kanggo obyek molah malih. Listing 3 nuduhake conto ing ngendi, nalika wiwitan, benang latar mburi ngemot sawetara data saka database. Kode liyane sing bisa nyoba nggunakake data iki mriksa kanggo ndeleng apa wis diterbitake sadurunge nyoba kanggo nggunakake. public class BackgroundFloobleLoader { public volatile Flooble theFlooble; public void initInBackground() { // делаем много всякого theFlooble = new Flooble(); // единственная запись в theFlooble } } public class SomeOtherClass { public void doWork() { while (true) { // чё-то там делаем... // используем theFolooble, но только если она готова if (floobleLoader.theFlooble != null) doSomething(floobleLoader.theFlooble); } } } Yen referensi kanggo Flooble ora molah malih, kode ing doWork () bakal resiko ndeleng Flooble sebagian dibangun nalika nyoba kanggo referensi Flooble. Syarat utama kanggo pola iki yaiku obyek sing diterbitake kudu aman utawa ora bisa diganti kanthi efektif (ora owah kanthi efektif tegese negarane ora bakal owah sawise diterbitake). Link volatile bisa mesthekake yen obyek katon ing wangun diterbitake, nanging yen kahanan obyek diganti sawise nerbitaké, sinkronisasi tambahan dibutuhake.
Pola #3: Observasi Mandhiri
Conto prasaja liyane saka nggunakake aman molah malih nalika pengamatan periodik "diterbitake" kanggo nggunakake ing program. Contone, ana sensor lingkungan sing ndeteksi suhu saiki. Utas latar mburi bisa maca sensor iki saben sawetara detik lan nganyari variabel molah malih ngemot suhu saiki. Utas liyane banjur bisa maca variabel iki, ngerti yen nilai kasebut tansah anyar. Panggunaan liya kanggo pola iki yaiku ngumpulake statistik babagan program kasebut. Listing 4 nuduhake carane mekanisme otentikasi bisa ngelingi jeneng pangguna pungkasan sing mlebu. Referensi LastUser bakal digunakake maneh kanggo ngirim nilai kanggo nggunakake program liyane. public class UserManager { public volatile String lastUser; public boolean authenticate(String user, String password) { boolean valid = passwordIsValid(user, password); if (valid) { User u = new User(); activeUsers.add(u); lastUser = user; } return valid; } } Pola iki ngembang ing sing sadurunge; Nilai diterbitake kanggo nggunakake ing panggonan liya ing program, nanging publikasi ora acara siji-wektu, nanging seri saka sawijining. Pola iki mbutuhake nilai sing diterbitake kanthi efektif ora bisa diganti - supaya negarane ora owah sawise diterbitake. Kode sing nggunakake nilai kasebut kudu dingerteni manawa bisa diganti kapan wae.
Pola # 4: pola "kacang molah malih".
Pola "kacang molah malih" ditrapake ing kerangka kerja sing nggunakake JavaBeans minangka "struktur sing dimuliakake". Pola "kacang molah malih" nggunakake JavaBean minangka wadhah kanggo klompok properti independen karo getter lan / utawa setter. Alesan kanggo pola "kacang molah malih" yaiku akeh kerangka sing nyedhiyakake wadhah kanggo wadhah data sing bisa diganti (kayata HttpSession), nanging obyek sing diselehake ing wadhah kasebut kudu aman. Ing pola kacang molah malih, kabeh unsur data JavaBean molah malih, lan getter lan setter kudu ora pati penting - padha ngirim ora ngemot logika liyane saka njupuk utawa nyetel properti sing cocog. Kajaba iku, kanggo anggota data sing referensi obyek, ngandika obyek kudu èfèktif immutable. (Iki ora ngidini kolom referensi array, amarga nalika referensi array diumumake molah malih, mung referensi kasebut, lan dudu unsur kasebut, duwe sifat molah malih.) Kaya variabel molah malih, ora ana invarian utawa watesan sing ana gandhengane karo sifat JavaBeans. . Conto JavaBean sing ditulis nggunakake pola "molah malih" ditampilake ing Listing 5: @ThreadSafe public class Person { private volatile String firstName; private volatile String lastName; private volatile int age; public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } public void setFirstName(String firstName) { this.firstName = firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public void setAge(int age) { this.age = age; } }
Pola molah malih sing luwih kompleks
Pola ing bagean sadurunge nyakup umume kasus sing nggunakake molah malih cukup wajar lan jelas. Bagean iki ndeleng pola sing luwih rumit sing bisa molah malih menehi keuntungan kinerja utawa skalabilitas. Pola molah malih sing luwih maju bisa dadi rapuh banget. Penting banget yen asumsi sampeyan didokumentasikake kanthi teliti lan pola kasebut dienkapsulasi kanthi kuat, amarga owah-owahan sing paling cilik bisa ngrusak kode sampeyan! Kajaba iku, amarga alasan utamane kasus panggunaan sing luwih rumit yaiku kinerja, priksa manawa sampeyan duwe kabutuhan sing jelas kanggo entuk kinerja sing dituju sadurunge nggunakake. Pola kasebut minangka kompromi sing ngorbanake keterbacaan utawa gampang dijaga supaya bisa entuk kinerja - yen sampeyan ora mbutuhake perbaikan kinerja (utawa ora bisa mbuktekake manawa sampeyan butuh program pangukuran sing ketat), mula bisa uga dadi masalah amarga sampeyan menehi munggah soko terkenal lan entuk soko kurang ing bali.
Pola #5: Kunci maca-tulis sing murah
Saiki sampeyan kudu ngerti manawa volatile banget banget kanggo ngetrapake counter. Wiwit ++x ateges nyuda telung operasi (maca, nambah, nyimpen), yen ana salah, sampeyan bakal kelangan nilai sing dianyari yen sawetara benang nyoba nambah counter molah malih bebarengan. Nanging, yen ana luwih akeh maca tinimbang owah-owahan, sampeyan bisa gabungke kunci intrinsik lan variabel molah malih kanggo nyuda overhead jalur kode sakabèhé. Listing 6 nuduhake counter thread-aman sing nggunakake diselarasake kanggo mesthekake yen operasi increment punika atom, lan nggunakake molah malih kanggo mesthekake yen asil saiki katon. Yen nganyari arang banget, pendekatan iki bisa nambah kinerja amarga biaya maca diwatesi kanggo maca molah malih, sing umume luwih murah tinimbang entuk kunci sing ora konflik. @ThreadSafe public class CheesyCounter { // Employs the cheap read-write lock trick // All mutative operations MUST be done with the 'this' lock held @GuardedBy("this") private volatile int value; public int getValue() { return value; } public synchronized int increment() { return value++; } } Alesane metode iki diarani "kunci maca-tulis sing murah" amarga sampeyan nggunakake mekanisme wektu sing beda kanggo maca lan nulis. Amarga nulis operasi ing kasus iki nglanggar kondisi pisanan nggunakake molah malih, sampeyan ora bisa nggunakake molah malih kanggo ngleksanakake counter aman - sampeyan kudu nggunakake kunci. Nanging, sampeyan bisa nggunakake molah malih kanggo nggawe nilai saiki katon nalika maca, supaya sampeyan nggunakake kunci kanggo kabeh operasi modifikasi lan molah malih kanggo mung diwaca operasi. Yen kunci mung ngidini siji utas ing siji wektu kanggo ngakses nilai, maca molah malih ngidini luwih saka siji, supaya nalika sampeyan nggunakake molah malih kanggo nglindhungi diwaca, sampeyan entuk tingkat ijol-ijolan sing luwih dhuwur tinimbang yen sampeyan nggunakake kunci ing kabeh kode: lan maca, lan cathetan. Nanging, elinga babagan fragility pola iki: kanthi rong mekanisme sinkronisasi sing saingan, bisa dadi rumit banget yen sampeyan ngluwihi aplikasi paling dhasar saka pola iki.
Ringkesan
Variabel volatil minangka wujud sinkronisasi sing luwih prasaja nanging luwih lemah tinimbang ngunci, sing ing sawetara kasus nyedhiyakake kinerja utawa skalabilitas sing luwih apik tinimbang ngunci intrinsik. Yen sampeyan nyukupi syarat kanggo nggunakake molah malih sing aman - variabel kasebut pancen bebas saka variabel liyane lan nilai sadurunge - sampeyan kadhangkala bisa nyederhanakake kode kanthi ngganti sinkronisasi karo molah malih. Nanging, kode sing nggunakake volatile asring luwih rapuh tinimbang kode sing nggunakake kunci. Pola sing disaranake ing kene kalebu kasus sing paling umum ing ngendi volatilitas minangka alternatif sing cukup kanggo sinkronisasi. Kanthi ngetutake pola kasebut - lan ngati-ati supaya ora ngluwihi watese dhewe - sampeyan bisa kanthi aman nggunakake molah malih ing kasus sing menehi keuntungan.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION