Uçucu boolean vs AtomicBoolean


244

AtomicBoolean, uçucu bir booleanın başaramadığını ne yapar?


16
Ben daha nüanslı bir cevap arıyordum: "her birinin sınırlamaları nelerdir?". Örneğin, bir iş parçacığı tarafından ayarlanan ve bir veya daha fazla başka kullanıcı tarafından okunan bir bayraksa, AtomicBoolean'a gerek yoktur. Ancak, bu cevaplarla gördüğüm gibi, eğer iş parçacığı birden çok iş parçacığında bir değişkeni paylaşıyorsa ve okumalarının sonucu üzerinde çalışıyorsa, AtomicBoolean CAS tipi kilitlemesiz işlemleri oyuna getirir. Aslında burada biraz öğreniyorum. Umarım, diğerleri de yararlanır.
JeffV


uçucu boolean, yarış koşullarını işlemek için açık senkronizasyona ihtiyaç duyacaktır, başka bir deyişle, paylaşılan kaynak gibi birden fazla iş parçacığı tarafından güncellenen (durum değişikliği) gibi senaryo, örneğin artış / azalma sayacı veya saygısız boolean gibi güncellenecektir.
sactiw

Yanıtlar:


99

Bunlar tamamen farklı. Şu volatiletamsayı örneğini ele alalım :

volatile int i = 0;
void incIBy5() {
    i += 5;
}

İki iş parçacığı aynı anda işlevi çağırırsa, iderlenmiş kod buna biraz benzer olacağı için (daha sonra eşitleyemezseniz int):

void incIBy5() {
    int temp;
    synchronized(i) { temp = i }
    synchronized(i) { i = temp + 5 }
}

Bir değişken uçucuysa, ona her atomik erişim senkronize edilir, ancak aslında bir atomik erişim olarak nitelendirilen şeyin ne olduğu her zaman açık değildir. Bir Atomic*nesne ile, her yöntemin "atom" olduğu garanti edilir.

Böylece, bir AtomicIntegerve kullanırsanız getAndAdd(int delta), sonucun olacağından emin olabilirsiniz 10. Aynı şekilde, eğer iki iş parçacığı bir booleandeğişkeni aynı anda olumsuzluyorsa , bir ile AtomicBooleandaha sonra orijinal değerine sahip olduğundan emin olabilirsiniz, a ile volatile booleanyapamazsınız.

Bu nedenle , bir alanı değiştiren birden fazla iş parçacığınız olduğunda, bunu atom haline getirmeniz veya açık senkronizasyon kullanmanız gerekir.

Amacı volatilefarklıdır. Bu örneği düşünün

volatile boolean stop = false;
void loop() {
    while (!stop) { ... }
}
void stop() { stop = true; }

Çalışan bir iş parçacığınız loop()ve başka bir iş parçacığı stop()çağrınız varsa volatile, ilk iş parçacığı durma değerini önbelleğe alabileceğinden, atlarsanız sonsuz bir döngüye girebilirsiniz . Burada, volatilederleyiciye optimizasyon konusunda biraz daha dikkatli olmanın bir ipucu olarak hizmet ediyor.


84
-1: örnekler veriyorsunuz ancak uçucu ve Atomicxxxx arasındaki farkı gerçekten açıklamıyorsunuz.
Jason S

70
Soru ilgili değil volatile. Soru volatile booleanvs ile ilgili AtomicBoolean.
dolmen

26
-1: özellikle diğer veri türlerine kıyasla benzersiz bir durum olan ve doğrudan açıklanması gereken boolean hakkında sorulan soru.
John Haager

8
@ sgp15 Java 5'ten itibaren senkronizasyon ile ilgilidir.
One of Man

6
Boole değeri birçok iş parçacığı tarafından okunuyor, ancak yalnızca bir iş parçacığı tarafından yazılıyorsa volatile booleanyeterli olur. Ayrıca çok sayıda yazar varsa, ihtiyacınız olabilir AtomicBoolean.
StvnBrkdll

263

Bahsedilen alan SADECE sahibinin iş parçacığı tarafından GÜNCELLEŞTİRİLDİĞİNDE ve değer yalnızca diğer iş parçacıkları tarafından okunduğunda uçucu alanlar kullanıyorum, bunu çok sayıda gözlemcinin olduğu sadece bir yayıncının olduğu bir yayınlama / abone olma senaryosu olarak düşünebilirsiniz. Ancak, bu gözlemciler alanın değerine bağlı olarak bir mantık gerçekleştirmeli ve sonra yeni bir değeri geri itmeli ise, o zaman Atomic * vars veya lock'lar veya senkronize bloklarla gidiyorum, bana en uygun olanı. Birçok eşzamanlı senaryoda, değeri almak, başka bir değerle karşılaştırmak ve gerekirse güncellemek, dolayısıyla Atomic * sınıflarında bulunan CompareAndSet ve getAndSet yöntemlerini bulmak için kaynar.

Atom sınıflarının bir listesi ve nasıl çalıştıklarına dair mükemmel bir açıklama için java.util.concurrent.atomic paketinin JavaDoc'larını kontrol edin (kilitsiz olduklarını öğrendik, böylece kilitler veya senkronize bloklar üzerinde bir avantajları var)


1
@ksl @teto sadece bir iş parçacığı booleanvar değişiklik , biz seçmeliyim tanımlamak istiyorum düşünüyorum volatile boolean.
znlyj

2
Mükemmel özet.
Ravindra babu

56

Sen yapamaz compareAndSet, getAndSetuçucu boolean atomik işlem olarak (tabii sürece senkronize).


6
Bu doğrudur, ancak bu bir boole için oldukça nadir bir gereklilik olmaz mı?
Robin

1
@ Robin, bir başlatma yönteminin tembel bir çağrılmasını kontrol etmek için kullanmayı düşünür.
Ustaman Sangat

Aslında bunun ana kullanım durumlarından biri olduğunu düşünürdüm.
fool4jesus

42

AtomicBooleanbileşik işlemlerini atomik olarak ve bir synchronizedblok kullanmak zorunda kalmadan gerçekleştiren yöntemlere sahiptir . Öte yandan, volatile booleanbileşik işlemleri ancak bir synchronizedblok içinde yapılırsa gerçekleştirilebilir .

Okuma / yazmanın hafıza etkileri sırasıyla ve yöntemleriyle volatile booleanaynıdır .getsetAtomicBoolean

Örneğin compareAndSetyöntem, atomik olarak aşağıdakileri gerçekleştirir ( synchronizedblok olmadan ):

if (value == expectedValue) {
    value = newValue;
    return true;
} else {
    return false;
}

Bu nedenle, compareAndSetyöntem, birden çok iş parçacığından çağrıldığında bile, yalnızca bir kez yürütülmesi garanti edilen kodu yazmanıza izin verir. Örneğin:

final AtomicBoolean isJobDone = new AtomicBoolean(false);

...

if (isJobDone.compareAndSet(false, true)) {
    listener.notifyJobDone();
}

Dinleyiciye yalnızca bir kez bildirimde bulunulması garanti edilir (başka bir iş parçacığının , ayarlandıktan sonra tekrar AtomicBooleanarkaya dönmediği varsayılırsa ).falsetrue


14

volatileanahtar kelime garantileri, bu değişkeni paylaşan evreler arasındaki ilişkiden önce gerçekleşir. Boolean değişkenine erişirken 2 veya daha fazla iş parçacığının birbirini kesmeyeceğini garanti etmez.


14
Boole (ilkel tipte olduğu gibi) erişim Java'da atomiktir. Hem okuma hem de ödev. Yani başka hiçbir evre boole işlemlerini "kesintiye uğratmaz".
Maciej Biłas

1
Üzgünüm ama bu soruya nasıl cevap veriyor? Bir Atomic*sınıf bir sarar volatilealan.
Gri

CPU, uçucu ayarlamak için ana faktörü önbelleğe almıyor mu? Okunan değerin aslında en son olarak ayarlandığından emin olmak için
jocull

8

Uçucu boolean vs AtomicBoolean

Atomic * sınıfları, aynı türdeki uçucu bir ilkeli sarar. Kaynaktan:

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;
   }

Yani tüm yaptığınız bir Atomik * alıp ayarlamaksa, bunun yerine sadece değişken bir alanınız olabilir.

AtomicBoolean, uçucu bir booleanın başaramadığını ne yapar?

Atom * dersler size gibi daha gelişmiş işlevsellik sağlamak yöntemleri vermek incrementAndGet(),compareAndSet() ve kilitleme olmadan çoklu işlemleri (get / artım / seti, test / kümesi) uygulamak diğerleri. Bu yüzden Atom * sınıfları çok güçlü.

Örneğin, birden çok iş parçacığı aşağıdaki kodu kullanarak kullanıyorsa ++, ++gerçekte olduğu gibi yarış koşulları olacaktır : get, increment ve set.

private volatile value;
...
// race conditions here
value++;

Ancak, aşağıdaki kod kilitsiz çok iş parçacıklı bir ortamda güvenle çalışır:

private final AtomicLong value = new AtomicLong();
...
value.incrementAndGet();

Uçucu alanınızı Atomic * sınıfı kullanarak kaydırmanın, kritik paylaşılan kaynağı bir nesne bakış açısından kapsüllemek için iyi bir yol olduğunu da unutmayın. Bu, geliştiricilerin alanla uğraşamayacağı anlamına gelir, ancak bir alan ++ ile muhtemelen enjekte edilen sorunlar paylaşılmaz; veya yarış koşullarını tanıtan diğer kodlar.


5

Sınıf düzeyi değişkenine erişen birden fazla iş parçacığı varsa, her iş parçacığı bu değişkenin kopyasını iş parçacığı önbelleğinde tutabilir.

Değişkeni geçici yapmak, iş parçacıklarının değişken kopyasını iş parçacığı önbelleğinde tutmasını önler.

Atomik değişkenler farklıdır ve değerlerinin atomik olarak değiştirilmesine izin verirler.


4

Boolean ilkel tip yazma ve okuma işlemleri için atomiktir, uçucu olmayan önce gerçekleşme ilkesini garanti eder. Eğer basit bir get () ve set () gerekiyorsa AtomicBoolean gerekmez.

Öte yandan, bir değişkenin değerini ayarlamadan önce bazı kontroller yapmanız gerekiyorsa, örneğin "true ise false olarak ayarlanırsa", bu işlemi atomik olarak da yapmanız gerekir, bu durumda CompareAndSet ve tarafından sağlanan diğer yöntemleri kullanın. AtomicBoolean, eğer bu mantığı uçucu boolean ile uygulamaya çalışırsanız, değerin get ve set arasında değişmediğinden emin olmak için bazı senkronizasyonlara ihtiyacınız olacaktır.


3

IDIOM'u hatırla -

OKUYUN - DEĞİŞTİRİN - uçucu ile elde edemeyeceğinizi YAZIN


2
Kısa, gevrek ve noktaya. volatileyalnızca sahipli iş parçacığının alan değerini güncelleme yeteneğine sahip olduğu durumlarda çalışır ve diğer iş parçacıkları yalnızca okuyabilir.
Chaklader Asfak Arefe

3

Boolean'ınızı değiştiren yalnızca bir iş parçacığınız varsa, geçici bir boolean kullanabilirsiniz (genellikle stopiş parçacığının ana döngüsünde kontrol edilen bir değişkeni tanımlamak için bunu yaparsınız ).

Ancak, boole'de değişiklik yapan birden fazla iş parçacığınız varsa, bir AtomicBoolean. Aksi takdirde, aşağıdaki kod güvenli değildir:

boolean r = !myVolatileBoolean;

Bu işlem iki adımda yapılır:

  1. Boole değeri okunur.
  2. Boolean değeri yazılır.

Başka bir iş parçacığı #1ve arasındaki değeri değiştirirse, 2#yanlış bir sonuç alabilirsiniz. AtomicBooleanyöntemler adım adım #1ve #2atomik olarak bu sorunu önler .


-1

Her ikisi de aynı konsepttedir ancak atomik boole'de cpu anahtarının arasında olması durumunda operasyona atomiklik sağlayacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.