AtomicBoolean, uçucu bir booleanın başaramadığını ne yapar?
AtomicBoolean, uçucu bir booleanın başaramadığını ne yapar?
Yanıtlar:
Bunlar tamamen farklı. Şu volatile
tamsayı örneğini ele alalım :
volatile int i = 0;
void incIBy5() {
i += 5;
}
İki iş parçacığı aynı anda işlevi çağırırsa, i
derlenmiş 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 AtomicInteger
ve kullanırsanız getAndAdd(int delta)
, sonucun olacağından emin olabilirsiniz 10
. Aynı şekilde, eğer iki iş parçacığı bir boolean
değişkeni aynı anda olumsuzluyorsa , bir ile AtomicBoolean
daha sonra orijinal değerine sahip olduğundan emin olabilirsiniz, a ile volatile boolean
yapamazsı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ı volatile
farklı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, volatile
derleyiciye optimizasyon konusunda biraz daha dikkatli olmanın bir ipucu olarak hizmet ediyor.
volatile
. Soru volatile boolean
vs ile ilgili AtomicBoolean
.
volatile boolean
yeterli olur. Ayrıca çok sayıda yazar varsa, ihtiyacınız olabilir AtomicBoolean
.
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)
boolean
var değişiklik , biz seçmeliyim tanımlamak istiyorum düşünüyorum volatile boolean
.
Sen yapamaz compareAndSet
, getAndSet
uçucu boolean atomik işlem olarak (tabii sürece senkronize).
AtomicBoolean
bileşik işlemlerini atomik olarak ve bir synchronized
blok kullanmak zorunda kalmadan gerçekleştiren yöntemlere sahiptir . Öte yandan, volatile boolean
bileşik işlemleri ancak bir synchronized
blok içinde yapılırsa gerçekleştirilebilir .
Okuma / yazmanın hafıza etkileri sırasıyla ve yöntemleriyle volatile boolean
aynıdır .get
set
AtomicBoolean
Örneğin compareAndSet
yöntem, atomik olarak aşağıdakileri gerçekleştirir ( synchronized
blok olmadan ):
if (value == expectedValue) {
value = newValue;
return true;
} else {
return false;
}
Bu nedenle, compareAndSet
yö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 AtomicBoolean
arkaya dönmediği varsayılırsa ).false
true
volatile
anahtar 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.
Atomic*
sınıf bir sarar volatile
alan.
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.
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.
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.
IDIOM'u hatırla -
OKUYUN - DEĞİŞTİRİN - uçucu ile elde edemeyeceğinizi YAZIN
volatile
yalnı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.
Boolean'ınızı değiştiren yalnızca bir iş parçacığınız varsa, geçici bir boolean kullanabilirsiniz (genellikle stop
iş 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:
Başka bir iş parçacığı #1
ve arasındaki değeri değiştirirse, 2#
yanlış bir sonuç alabilirsiniz. AtomicBoolean
yöntemler adım adım #1
ve #2
atomik olarak bu sorunu önler .
Her ikisi de aynı konsepttedir ancak atomik boole'de cpu anahtarının arasında olması durumunda operasyona atomiklik sağlayacaktır.