Volatile boolean vs AtomicBoolean

245

Apa yang dilakukan AtomicBoolean yang tidak dapat dicapai oleh boolean yang mudah menguap?

JeffV
sumber
16
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.
JeffV
1
kemungkinan rangkap dari boolean yang mudah menguap vs AtomicBoolean
Aliran
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.
sactiw

Jawaban:

98

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.

Cephalopod
sumber
84
-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)

teto
sumber
1
@ksl Saya pikir @teto ingin menjelaskan bahwa jika hanya satu utas memodifikasi booleanvar, kita harus memilih volatile boolean.
znlyj
2
Ringkasan yang luar biasa.
Ravindra babu
56

Anda tidak bisa melakukannya compareAndSet , getAndSetkarena operasi atom dengan volatile boolean (kecuali tentu saja Anda menyinkronkannya).

nanda
sumber
6
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;
    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).

Nam San
sumber
14

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.

dhblah
sumber
14
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:

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.

Abu-abu
sumber
5

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.

Amol Gaikwad
sumber
5

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.

pengguna2660000
sumber
3

Ingat IDIOM -

BACA - MODIFIKASI - MENULIS ini Anda tidak dapat mencapai dengan volatile

Bergerak cepat
sumber
2
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:

  1. Nilai boolean dibaca.
  2. 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.

Thibaut D.
sumber
"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.

Bismaya Mohapatra
sumber