Apa yang dilakukan AtomicBoolean yang tidak dapat dicapai oleh boolean yang mudah menguap?
Apa yang dilakukan AtomicBoolean yang tidak dapat dicapai oleh boolean yang mudah menguap?
Jawaban:
Mereka sama sekali berbeda. Pertimbangkan contoh volatilebilangan bulat ini:
volatile int 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
volatile boolean stop = false;
void loop() {
while (!stop) { ... }
}
void stop() { stop = true; }
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.
volatile. Pertanyaannya adalah tentang volatile booleanvs AtomicBoolean.
volatile booleansudah cukup. Jika ada banyak penulis, Anda mungkin perlu AtomicBoolean.
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)
booleanvar, kita harus memilih volatile boolean.
Anda tidak bisa melakukannya compareAndSet , getAndSetkarena operasi atom dengan volatile boolean (kecuali tentu saja Anda menyinkronkannya).
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;
return true;
} else {
return false;
}
Oleh karena itu, compareAndSetmetode ini akan membiarkan Anda menulis kode yang dijamin untuk dieksekusi hanya sekali, bahkan ketika dipanggil dari banyak utas. Sebagai contoh:
final AtomicBoolean isJobDone = new AtomicBoolean(false);
...
if (isJobDone.compareAndSet(false, true)) {
listener.notifyJobDone();
}
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.
Atomic*kelas membungkus volatilelapangan.
Volatile boolean vs AtomicBoolean
Kelas Atomic membungkus primitif yang mudah menguap dari jenis yang sama. Dari sumber:
public class AtomicLong extends Number implements java.io.Serializable {
...
private volatile long value;
...
public final long get() {
return value;
}
...
public final void 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.
private volatile value;
...
// race conditions here
value++;
Namun, kode berikut akan bekerja di lingkungan multi-utas dengan aman tanpa kunci:
private final AtomicLong value = new AtomicLong();
...
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.
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.
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.
Ingat IDIOM -
BACA - MODIFIKASI - MENULIS ini Anda tidak dapat mencapai dengan volatile
volatilehanya 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 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:
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.
Keduanya memiliki konsep yang sama tetapi dalam boolean atom itu akan memberikan atomicity untuk operasi jika cpu switch terjadi di antaranya.