Kapan saya perlu menggunakan AtomicBoolean di Java?

Jawaban:

244

Ketika beberapa utas perlu memeriksa dan mengubah boolean. Sebagai contoh:

if (!initialized) {
   initialize();
   initialized = true;
}

Ini bukan thread-safe. Anda dapat memperbaikinya dengan menggunakan AtomicBoolean:

if (atomicInitialized.compareAndSet(false, true)) {
    initialize();
}
Bozho
sumber
51
Itu tidak terlihat seperti contoh dunia nyata - utas lainnya dapat melihat truekapan initialize()belum selesai. Jadi, ini hanya berfungsi jika utas lainnya tidak peduli penyelesaiannya initialize().
axtavt
6
@axtavt: Saya pikir ini adalah contoh dunia nyata yang benar-benar valid jika initializedhanya digunakan untuk memastikan bahwa satu dan hanya satu utas akan memanggil initialize()metode. Jelas initializedbenar bukan berarti inisialisasi telah selesai dalam kasus ini, jadi mungkin istilah yang sedikit berbeda akan lebih baik di sini. Sekali lagi, itu tergantung pada apa yang digunakan untuk itu.
ColinD
14
Anda akan membutuhkan 2 booleans untuk initStarted dan initCompleted, kemudian utas pertama menetapkan initStarted dan memanggil inisialisasi (), sisanya menunggu hingga initCompleted benar.
Martin
3
@ Bozho - membaca dan menulis ke bidang boolean adalah atom kan ?, Sekarang, volatile memberi saya nilai terbaru dari bidang boolean. Jadi, secara efektif, tidak volatile booleanakan sama dengan AtomicBoolean?
TheLostMind
2
@ Martin: Tidak ada cara langsung untuk menunggu boolean menjadi kenyataan; Anda memerlukan mekanisme tambahan. Pendekatan yang paling masuk akal adalah dengan menggunakan synchronizedblok, dalam hal ini Anda tidak perlu lagi AtomicBoolean, hanya a volatile boolean. ( if(! this.initialized) { synchronized(this) { if(! this.initialized) { initialize(); this.initialized = true; } } }akan memastikan bahwa hanya satu utas panggilan initialize, dan bahwa semua utas lainnya menunggu untuk melakukannya, asalkan initializedditandai volatile.)
ruakh
52

Ini adalah catatan (dari buku Brian Goetz ) yang saya buat, yang mungkin bisa membantu Anda

Kelas AtomicXXX

  • menyediakan implementasi Bandingkan-dan-Tukar Non-pemblokiran

  • Mengambil keuntungan dari dukungan yang diberikan oleh perangkat keras (instruksi CMPXCHG pada Intel) Ketika banyak utas berjalan melalui kode Anda yang menggunakan API konkurensi atom ini, mereka akan berskala jauh lebih baik daripada kode yang menggunakan monitor / sinkronisasi tingkat objek. Karena, mekanisme sinkronisasi Java membuat kode menunggu, ketika ada banyak utas yang berjalan melalui bagian-bagian penting Anda, banyak waktu CPU dihabiskan untuk mengelola mekanisme sinkronisasi itu sendiri (menunggu, memberi tahu, dll.). Karena API baru menggunakan konstruksi tingkat perangkat keras (variabel atom) dan menunggu dan mengunci algoritma gratis untuk menerapkan keamanan ulir, lebih banyak waktu CPU dihabiskan untuk "melakukan hal-hal" daripada mengelola sinkronisasi.

  • tidak hanya menawarkan throughput yang lebih baik, tetapi mereka juga memberikan perlawanan yang lebih besar terhadap masalah kehidupan seperti kebuntuan dan inversi prioritas.

Aravind Yarram
sumber
34

Ada dua alasan utama mengapa Anda dapat menggunakan boolean atom. Pertama bisa berubah, Anda bisa meneruskannya sebagai referensi dan mengubah nilai yang terkait dengan boolean itu sendiri, misalnya.

public final class MyThreadSafeClass{

    private AtomicBoolean myBoolean = new AtomicBoolean(false);
    private SomeThreadSafeObject someObject = new SomeThreadSafeObject();

    public boolean doSomething(){
         someObject.doSomeWork(myBoolean);
         return myBoolean.get(); //will return true
    }
}

dan di kelas someObject

public final class SomeThreadSafeObject{
    public void doSomeWork(AtomicBoolean b){
        b.set(true);
    }
}

Lebih penting lagi, utasnya aman dan dapat menunjukkan kepada pengembang yang menjaga kelas, bahwa variabel ini diharapkan akan dimodifikasi dan dibaca dari beberapa utas. Jika Anda tidak menggunakan AtomicBoolean, Anda harus menyinkronkan variabel boolean yang Anda gunakan dengan mendeklarasikannya volatil atau menyinkronkan sekitar bidang baca dan tulis bidang.

John Vint
sumber
4
Untuk cinta tuhan, itu hanya untuk menunjukkan sifat tidak berubah dari objek itu sendiri. Saya secara khusus menulis itu untuk tujuan demonstrasi.
John Vint
Dan lebih jauh lagi, jika itu SEMUA yang terjadi maka ya, itu akan selalu kembali benar
John Vint
Itu tidak membuktikan apakah itu aman atau tidak. Saya dapat menyelesaikan cuplikan kode saya untuk membuat kelas sangat aman, tetapi itu hanya membunuh poin saya.
John Vint
1
Saya pikir hanya Volatile saja tidak cukup. Pikirkan tentang situasi di mana dua utas yang membaca dan menulis nilai yang sama langsung dari memori utama, tidak ada sinkronisasi antara utas tersebut - hance masalah konkurensi mungkin muncul.
Shay Tsadok
1
Anda benar itu tidak akan cukup untuk set atom kemudian memeriksa operasi, meskipun tidak ada konteks yang cukup dari OP untuk membuat asumsi itu. Untuk mengatakan, volatile mungkin tidak cukup selalu benar tergantung pada situasi, tentu saja.
John Vint
18

The AtomicBooleankelas memberi Anda nilai boolean yang Anda dapat memperbarui atom. Gunakan ketika Anda memiliki banyak utas yang mengakses variabel boolean.

The gambaran paket java.util.concurrent.atomic memberikan gambaran tingkat tinggi baik dari apa kelas dalam paket ini dilakukan dan kapan menggunakannya. Saya juga merekomendasikan buku Java Concurrency in Practice oleh Brian Goetz.

Cameron Skinner
sumber
5

Kutipan dari deskripsi paket

Paket deskripsi java.util.concurrent.atomic: Toolkit kecil dari kelas yang mendukung pemrograman bebas-penguncian bebas-kunci pada variabel tunggal. [...]

Spesifikasi dari metode ini memungkinkan implementasi untuk menggunakan instruksi atom tingkat mesin yang efisien yang tersedia pada prosesor kontemporer. [...]

Contoh kelas AtomicBoolean, AtomicInteger, AtomicLong, dan AtomicReference masing-masing memberikan akses dan pembaruan ke satu variabel dari jenis yang sesuai. [...]

Efek memori untuk akses dan pembaruan atom umumnya mengikuti aturan untuk volatil:

  • dapatkan memiliki efek memori dari membaca variabel volatile.
  • set memiliki efek memori menulis (menugaskan) variabel yang mudah menguap.
  • lemahCompareAndSet secara atom membaca dan kondisional menulis variabel, diperintahkan sehubungan dengan operasi memori lain pada variabel itu, tetapi sebaliknya bertindak sebagai operasi memori non-volatil biasa.
  • compareAndSet dan semua operasi baca-dan-perbarui lainnya seperti getAndIncrement memiliki efek memori dari membaca dan menulis variabel volatil.
OscarRyz
sumber