Saya mencari jawaban yang lebih bernuansa: "apa keterbatasan masing-masing?". Misalnya, jika adalah sebuah bendera yang ditetapkan oleh satu utas dan dibaca oleh satu atau lebih yang lain, tidak perlu untuk AtomicBoolean. Namun, seperti yang saya lihat dengan jawaban-jawaban ini, jika utas berbagi variabel dalam beberapa utas dapat menulis dan bertindak berdasarkan hasil bacaan mereka, AtomicBoolean membawa operasi non-penguncian tipe CAS. Saya belajar sedikit di sini, sebenarnya. Semoga orang lain juga mendapat manfaat.
volatile boolean akan membutuhkan sinkronisasi eksplisit untuk menangani kondisi balapan, dengan kata lain, skenario seperti sumber daya bersama diperbarui (perubahan status) dengan beberapa utas misalnya penghitung kenaikan / penurunan atau pembalikan boolean.
Mereka sama sekali berbeda. Pertimbangkan contoh volatilebilangan bulat ini:
volatileint i =0;void incIBy5(){
i +=5;}
Jika dua utas memanggil fungsi secara bersamaan, imungkin 5 setelahnya, karena kode yang dikompilasi akan agak mirip dengan ini (kecuali Anda tidak dapat menyinkronkan aktif int):
void incIBy5(){int temp;synchronized(i){ temp = i }synchronized(i){ i = temp +5}}
Jika suatu variabel volatil, setiap akses atom ke sana disinkronkan, tetapi tidak selalu jelas apa yang sebenarnya memenuhi syarat sebagai akses atom. Dengan sebuah Atomic*objek, dijamin bahwa setiap metode adalah "atom".
Jadi, jika Anda menggunakan AtomicIntegerdan getAndAdd(int delta), Anda dapat yakin bahwa hasilnya akan 10. Dengan cara yang sama, jika dua utas keduanya meniadakan booleanvariabel secara bersamaan, dengan AtomicBooleanAnda dapat yakin itu memiliki nilai asli setelahnya, dengan volatile boolean, Anda tidak bisa.
Jadi, setiap kali Anda memiliki lebih dari satu utas memodifikasi bidang, Anda harus membuatnya atomik atau menggunakan sinkronisasi eksplisit.
Tujuannya volatileberbeda. Pertimbangkan contoh ini
Jika Anda memiliki utas berjalan loop()dan utas lain memanggil stop(), Anda mungkin mengalami infinite loop jika Anda hilangkan volatile, karena utas pertama mungkin men-cache nilai stop. Di sini, volatileberfungsi sebagai petunjuk bagi kompiler untuk sedikit lebih berhati-hati dengan optimisasi.
-1: Anda memberikan contoh tetapi tidak benar-benar menjelaskan perbedaan antara volatil dan Atomicxxxx.
Jason S
70
Pertanyaannya bukan tentang volatile. Pertanyaannya adalah tentang volatile booleanvs AtomicBoolean.
dolmen
26
-1: pertanyaan yang secara khusus ditanyakan tentang boolean, yang merupakan kasus unik dibandingkan dengan tipe data lainnya dan harus dijelaskan secara langsung.
John Haager
8
@ sgp15 Ada hubungannya dengan sinkronisasi pada Java 5.
Man of One Way
6
Jika nilai boolean dibaca oleh banyak utas, tetapi hanya ditulis oleh satu utas, maka volatile booleansudah cukup. Jika ada banyak penulis, Anda mungkin perlu AtomicBoolean.
StvnBrkdll
263
Saya menggunakan bidang volatil ketika bidang tersebut HANYA DIPERBARUI oleh utas pemiliknya dan nilainya hanya dibaca oleh utas lainnya, Anda dapat menganggapnya sebagai skenario terbitkan / berlangganan di mana terdapat banyak pengamat tetapi hanya satu penerbit. Namun jika pengamat tersebut harus melakukan beberapa logika berdasarkan pada nilai bidang dan kemudian mendorong kembali nilai baru maka saya pergi dengan vars Atomic atau kunci atau blok yang disinkronkan, apa pun yang paling cocok untuk saya. Dalam banyak skenario bersamaan, intinya adalah untuk mendapatkan nilai, membandingkannya dengan yang lain dan memperbarui jika perlu, karenanya metode compareAndSet dan getAndSet hadir di kelas Atomic *.
Periksa JavaDocs dari paket java.util.concurrent.atomic untuk daftar kelas Atom dan penjelasan yang sangat baik tentang cara kerjanya (baru mengetahui bahwa mereka bebas kunci, sehingga mereka memiliki keunggulan dibandingkan kunci atau blok yang disinkronkan)
Ini benar, tetapi bukankah ini merupakan persyaratan yang cukup langka untuk boolean?
Robin
1
@Robin berpikir untuk menggunakannya untuk mengontrol pemanggilan metode inisialisasi yang malas.
Ustaman Sangat
Sebenarnya saya akan berpikir ini adalah salah satu kasus penggunaan utama.
fool4jesus
42
AtomicBooleanmemiliki metode yang melakukan operasi senyawa mereka secara atom dan tanpa harus menggunakan synchronizedblok. Di samping itu,volatile boolean hanya dapat melakukan operasi gabungan jika dilakukan dalam synchronizedblok.
Efek memori dari membaca / menulis volatile booleanidentik dengan getdan setmetodeAtomicBoolean masing masing.
Misalnya compareAndSetmetode akan melakukan hal berikut secara atomis (tanpa synchronizedblok):
if(value == expectedValue){
value = newValue;returntrue;}else{returnfalse;}
Oleh karena itu, compareAndSetmetode ini akan membiarkan Anda menulis kode yang dijamin untuk dieksekusi hanya sekali, bahkan ketika dipanggil dari banyak utas. Sebagai contoh:
Dijamin hanya akan memberi tahu pendengar sekali (dengan asumsi tidak ada utas lain yang mengatur AtomicBooleankembali falselagi setelah disetel ke true).
volatilejaminan kata kunci terjadi sebelum hubungan antara utas yang berbagi variabel itu. Itu tidak menjamin Anda bahwa 2 utas atau lebih tidak akan saling mengganggu saat mengakses variabel boolean itu.
Akses Boolean (seperti pada tipe primitif) adalah atom di Jawa. Keduanya membaca dan tugas. Jadi tidak ada utas lain yang akan "mengganggu" operasi boolean.
Maciej Biłas
1
Maaf, tetapi bagaimana ini menjawab pertanyaan? Sebuah Atomic*kelas membungkus volatilelapangan.
Gray
Bukankah CPU cache faktor utama untuk pengaturan volatile? Untuk memastikan bahwa nilai yang dibaca sebenarnya adalah apa yang ditetapkan untuk yang terbaru
jocull
8
Volatile boolean vs AtomicBoolean
Kelas Atomic membungkus primitif yang mudah menguap dari jenis yang sama. Dari sumber:
publicclassAtomicLongextendsNumberimplements java.io.Serializable{...privatevolatilelong value;...publicfinallong get(){return value;}...publicfinalvoid set(long newValue){
value = newValue;}
Jadi jika semua yang Anda lakukan adalah mendapatkan dan mengatur Atom * maka Anda mungkin hanya memiliki bidang yang mudah menguap.
Apa yang dilakukan AtomicBoolean yang tidak dapat dicapai oleh boolean yang mudah menguap?
Kelas Atom * memberi Anda metode yang memberikan fungsionalitas lebih lanjut seperti incrementAndGet() , compareAndSet(), dan lain-lain yang mengimplementasikan beberapa operasi (get / increment / set, uji / set) tanpa penguncian. Itu sebabnya kelas * Atom sangat kuat.
Misalnya, jika beberapa utas menggunakan kode berikut ++, akan ada kondisi balapan karena ++sebenarnya: dapatkan, tambah, dan tetapkan.
privatevolatile value;...// race conditions here
value++;
Namun, kode berikut akan bekerja di lingkungan multi-utas dengan aman tanpa kunci:
privatefinalAtomicLong value =newAtomicLong();...
value.incrementAndGet();
Penting juga untuk dicatat bahwa membungkus bidang volatil Anda menggunakan kelas Atom * adalah cara yang baik untuk merangkum sumber daya kritis bersama dari sudut pandang objek. Ini berarti bahwa pengembang tidak bisa hanya berurusan dengan bidang dengan asumsi itu tidak dibagikan kemungkinan menyuntikkan masalah dengan bidang ++; atau kode lain yang memperkenalkan kondisi lomba.
Tipe primitif Boolean adalah atom untuk operasi tulis dan baca, volatile menjamin prinsip yang terjadi sebelum. Jadi jika Anda membutuhkan get () dan set () yang sederhana maka Anda tidak perlu AtomicBoolean.
Di sisi lain, jika Anda perlu menerapkan beberapa pemeriksaan sebelum menetapkan nilai variabel, misalnya "jika benar lalu disetel ke false", maka Anda perlu melakukan operasi ini secara atomik, dalam hal ini gunakan compareAndSet dan metode lain yang disediakan oleh AtomicBoolean, karena jika Anda mencoba menerapkan logika ini dengan volatile boolean Anda akan memerlukan beberapa sinkronisasi untuk memastikan bahwa nilainya tidak berubah antara get dan set.
Pendek, renyah dan to the point. volatilehanya berfungsi dalam kasus di mana utas pemilik memiliki kemampuan untuk memperbarui nilai bidang dan utas lainnya hanya bisa membaca.
Chaklader Asfak Arefe
3
Jika Anda hanya memiliki satu utas memodifikasi boolean Anda, Anda dapat menggunakan boolean yang mudah menguap (biasanya Anda melakukan ini untuk menentukanstop variabel yang dicentang di loop utama utas).
Namun, jika Anda memiliki banyak utas memodifikasi boolean, Anda harus menggunakan AtomicBoolean. Selain itu, kode berikut tidak aman:
boolean r =!myVolatileBoolean;
Operasi ini dilakukan dalam dua langkah:
Nilai boolean dibaca.
Nilai boolean ditulis.
Jika utas lain mengubah nilai antara #1dan 2#, Anda mungkin mendapat hasil yang salah. AtomicBooleanmetode menghindari masalah ini dengan melakukan langkah-langkah #1dan #2secara atomis.
"Jika Anda hanya memiliki satu utas memodifikasi boolean Anda, Anda dapat menggunakan boolean yang mudah menguap." Lalu Jika Anda menggunakan satu utas, mengapa Anda perlu volatil (?) .. Anda harus menghapus paragraf pertama untuk membuat jawaban lebih baik ..
minsk
-1
Keduanya memiliki konsep yang sama tetapi dalam boolean atom itu akan memberikan atomicity untuk operasi jika cpu switch terjadi di antaranya.
Jawaban:
Mereka sama sekali berbeda. Pertimbangkan contoh
volatile
bilangan bulat ini:Jika dua utas memanggil fungsi secara bersamaan,
i
mungkin 5 setelahnya, karena kode yang dikompilasi akan agak mirip dengan ini (kecuali Anda tidak dapat menyinkronkan aktifint
):Jika suatu variabel volatil, setiap akses atom ke sana disinkronkan, tetapi tidak selalu jelas apa yang sebenarnya memenuhi syarat sebagai akses atom. Dengan sebuah
Atomic*
objek, dijamin bahwa setiap metode adalah "atom".Jadi, jika Anda menggunakan
AtomicInteger
dangetAndAdd(int delta)
, Anda dapat yakin bahwa hasilnya akan10
. Dengan cara yang sama, jika dua utas keduanya meniadakanboolean
variabel secara bersamaan, denganAtomicBoolean
Anda dapat yakin itu memiliki nilai asli setelahnya, denganvolatile boolean
, Anda tidak bisa.Jadi, setiap kali Anda memiliki lebih dari satu utas memodifikasi bidang, Anda harus membuatnya atomik atau menggunakan sinkronisasi eksplisit.
Tujuannya
volatile
berbeda. Pertimbangkan contoh iniJika Anda memiliki utas berjalan
loop()
dan utas lain memanggilstop()
, Anda mungkin mengalami infinite loop jika Anda hilangkanvolatile
, karena utas pertama mungkin men-cache nilai stop. Di sini,volatile
berfungsi sebagai petunjuk bagi kompiler untuk sedikit lebih berhati-hati dengan optimisasi.sumber
volatile
. Pertanyaannya adalah tentangvolatile boolean
vsAtomicBoolean
.volatile boolean
sudah cukup. Jika ada banyak penulis, Anda mungkin perluAtomicBoolean
.Saya menggunakan bidang volatil ketika bidang tersebut HANYA DIPERBARUI oleh utas pemiliknya dan nilainya hanya dibaca oleh utas lainnya, Anda dapat menganggapnya sebagai skenario terbitkan / berlangganan di mana terdapat banyak pengamat tetapi hanya satu penerbit. Namun jika pengamat tersebut harus melakukan beberapa logika berdasarkan pada nilai bidang dan kemudian mendorong kembali nilai baru maka saya pergi dengan vars Atomic atau kunci atau blok yang disinkronkan, apa pun yang paling cocok untuk saya. Dalam banyak skenario bersamaan, intinya adalah untuk mendapatkan nilai, membandingkannya dengan yang lain dan memperbarui jika perlu, karenanya metode compareAndSet dan getAndSet hadir di kelas Atomic *.
Periksa JavaDocs dari paket java.util.concurrent.atomic untuk daftar kelas Atom dan penjelasan yang sangat baik tentang cara kerjanya (baru mengetahui bahwa mereka bebas kunci, sehingga mereka memiliki keunggulan dibandingkan kunci atau blok yang disinkronkan)
sumber
boolean
var, kita harus memilihvolatile boolean
.Anda tidak bisa melakukannya
compareAndSet
,getAndSet
karena operasi atom dengan volatile boolean (kecuali tentu saja Anda menyinkronkannya).sumber
AtomicBoolean
memiliki metode yang melakukan operasi senyawa mereka secara atom dan tanpa harus menggunakansynchronized
blok. Di samping itu,volatile boolean
hanya dapat melakukan operasi gabungan jika dilakukan dalamsynchronized
blok.Efek memori dari membaca / menulis
volatile boolean
identik denganget
danset
metodeAtomicBoolean
masing masing.Misalnya
compareAndSet
metode akan melakukan hal berikut secara atomis (tanpasynchronized
blok):Oleh karena itu,
compareAndSet
metode ini akan membiarkan Anda menulis kode yang dijamin untuk dieksekusi hanya sekali, bahkan ketika dipanggil dari banyak utas. Sebagai contoh:Dijamin hanya akan memberi tahu pendengar sekali (dengan asumsi tidak ada utas lain yang mengatur
AtomicBoolean
kembalifalse
lagi setelah disetel ketrue
).sumber
volatile
jaminan kata kunci terjadi sebelum hubungan antara utas yang berbagi variabel itu. Itu tidak menjamin Anda bahwa 2 utas atau lebih tidak akan saling mengganggu saat mengakses variabel boolean itu.sumber
Atomic*
kelas membungkusvolatile
lapangan.Kelas Atomic membungkus primitif yang mudah menguap dari jenis yang sama. Dari sumber:
Jadi jika semua yang Anda lakukan adalah mendapatkan dan mengatur Atom * maka Anda mungkin hanya memiliki bidang yang mudah menguap.
Kelas Atom * memberi Anda metode yang memberikan fungsionalitas lebih lanjut seperti
incrementAndGet()
,compareAndSet()
, dan lain-lain yang mengimplementasikan beberapa operasi (get / increment / set, uji / set) tanpa penguncian. Itu sebabnya kelas * Atom sangat kuat.Misalnya, jika beberapa utas menggunakan kode berikut
++
, akan ada kondisi balapan karena++
sebenarnya: dapatkan, tambah, dan tetapkan.Namun, kode berikut akan bekerja di lingkungan multi-utas dengan aman tanpa kunci:
Penting juga untuk dicatat bahwa membungkus bidang volatil Anda menggunakan kelas Atom * adalah cara yang baik untuk merangkum sumber daya kritis bersama dari sudut pandang objek. Ini berarti bahwa pengembang tidak bisa hanya berurusan dengan bidang dengan asumsi itu tidak dibagikan kemungkinan menyuntikkan masalah dengan bidang ++; atau kode lain yang memperkenalkan kondisi lomba.
sumber
Jika ada beberapa utas yang mengakses variabel level kelas maka setiap utas dapat menyimpan salinan variabel itu dalam cache threadlocal-nya.
Membuat variabel volatile akan mencegah thread menyimpan salinan variabel dalam cache threadlocal.
Variabel atom berbeda dan mereka memungkinkan modifikasi atom dari nilainya.
sumber
Tipe primitif Boolean adalah atom untuk operasi tulis dan baca, volatile menjamin prinsip yang terjadi sebelum. Jadi jika Anda membutuhkan get () dan set () yang sederhana maka Anda tidak perlu AtomicBoolean.
Di sisi lain, jika Anda perlu menerapkan beberapa pemeriksaan sebelum menetapkan nilai variabel, misalnya "jika benar lalu disetel ke false", maka Anda perlu melakukan operasi ini secara atomik, dalam hal ini gunakan compareAndSet dan metode lain yang disediakan oleh AtomicBoolean, karena jika Anda mencoba menerapkan logika ini dengan volatile boolean Anda akan memerlukan beberapa sinkronisasi untuk memastikan bahwa nilainya tidak berubah antara get dan set.
sumber
Ingat IDIOM -
BACA - MODIFIKASI - MENULIS ini Anda tidak dapat mencapai dengan volatile
sumber
volatile
hanya berfungsi dalam kasus di mana utas pemilik memiliki kemampuan untuk memperbarui nilai bidang dan utas lainnya hanya bisa membaca.Jika Anda hanya memiliki satu utas memodifikasi boolean Anda, Anda dapat menggunakan boolean yang mudah menguap (biasanya Anda melakukan ini untuk menentukan
stop
variabel yang dicentang di loop utama utas).Namun, jika Anda memiliki banyak utas memodifikasi boolean, Anda harus menggunakan
AtomicBoolean
. Selain itu, kode berikut tidak aman:Operasi ini dilakukan dalam dua langkah:
Jika utas lain mengubah nilai antara
#1
dan2#
, Anda mungkin mendapat hasil yang salah.AtomicBoolean
metode menghindari masalah ini dengan melakukan langkah-langkah#1
dan#2
secara atomis.sumber
Keduanya memiliki konsep yang sama tetapi dalam boolean atom itu akan memberikan atomicity untuk operasi jika cpu switch terjadi di antaranya.
sumber