Yanıtlar:
Java'da statik bir değişken bildirmek , sınıfın kaç nesnesi oluşturulursa oluşturulsun, yalnızca bir kopya olacağı anlamına gelir. Değişken, hiç Objects
oluşturulmamış olsa bile erişilebilir . Ancak, evrelerin yerel olarak önbelleğe alınmış değerleri olabilir.
Bir değişken uçucu olduğunda ve statik olmadığında, her biri için bir değişken olacaktır Object
. Yani, yüzeyde normal bir değişkenten fark yok, ancak statikten tamamen farklı gibi görünüyor . Ancak, Object
alanlarla bile , bir iş parçacığı değişken değerini yerel olarak önbelleğe alabilir.
Bu, iki iş parçacığının aynı Nesnenin bir değişkenini aynı anda güncelleştirmesi ve değişkenin geçici olarak bildirilmemesi durumunda, iş parçacığından birinin önbellekte eski bir değere sahip olduğu bir durum olabileceği anlamına gelir.
Statik bir değere birden çok iş parçacığı aracılığıyla erişseniz bile , her iş parçacığının yerel önbelleğe alınmış kopyası olabilir! Bundan kaçınmak için, değişkeni statik geçici olarak bildirebilirsiniz ve bu, iş parçacığının her küresel değerde okumaya zorlar.
Ancak, uçucu düzgün senkronizasyonun yerini tutmaz!
Örneğin:
private static volatile int counter = 0;
private void concurrentMethodWrong() {
counter = counter + 5;
//do something
counter = counter - 5;
}
concurrentMethodWrong
Eşzamanlı olarak birçok kez çalıştırmak sıfırdan farklı bir sayacın nihai değerine yol açabilir!
Sorunu çözmek için bir kilit uygulamalısınız:
private static final Object counterLock = new Object();
private static volatile int counter = 0;
private void concurrentMethodRight() {
synchronized (counterLock) {
counter = counter + 5;
}
//do something
synchronized (counterLock) {
counter = counter - 5;
}
}
Veya AtomicInteger
sınıfı kullanın .
Statik ve Uçucu Arasındaki Fark:
Statik Değişken : İki konu (varsayalım ederse t1
ve t2
) aynı nesneyi erişmekte ve anlama ardından statik olarak bildirilmiş bir değişken güncelliyoruz t1
ve t2
kendi önbelleğinde (statik değişkenler dahil) aynı nesnenin kendi yerel kopyasını yapabilir, böylece güncelleme tarafından t1
yerel önbellekteki statik değişken tarafından yapılan t2
önbellek için statik değişkeni yansıtmaz .
Statik değişkenler, bir nesne tarafından yapılan güncellemenin aynı sınıftaki diğer tüm nesnelere yansıyacağı ancak bir iş parçacığının statik değişkene güncellemesinin hemen tüm değişikliklere yansıyacağı Thread bağlamında kullanılmayan Object bağlamında kullanılır. iş parçacıkları (yerel önbelleklerinde).
Uçucu değişken : İki İş parçacığı (varsayalım t1
ve t2
) aynı nesneye erişiyorsa ve uçucu olarak bildirilen bir değişkeni güncelliyorsa, uçucu olarak bildirilen değişken dışında Nesnenin kendi yerel önbelleğini oluşturabilir t1
ve t2
yapabilir . Dolayısıyla, değişken değişken, farklı evreler tarafından güncellenecek tek bir ana kopyaya sahip olacak ve bir evre tarafından geçici değişkene yapılan güncelleme hemen diğer Evreye yansıyacaktır.
volatile
değişken bile farklı CPU önbellekleri arasında paylaşılabilir. Önbellek, değiştirilmeden önce önbellek satırının münhasır sahipliğini görüştüğü için bu sorun yaratmaz.
Diğer cevaplara ek olarak, bunun için bir resim eklemek istiyorum (pic anlaşılmasını kolaylaştırıyor)
static
değişkenler tek tek evreler için önbelleğe alınabilir. Çok iş parçacıklı bir ortamda bir iş parçacığı önbelleğe alınmış verilerini değiştirirse, bu iş parçacığı bir kopyası olduğu için diğer iş parçacıklarını yansıtmayabilir .
volatile
bildirimi, iş parçacıklarının verileri önbelleğe almamasını sağlar ve yalnızca paylaşılan kopyayı kullanır .
Bence static
ve volatile
tüm hiçbir ilişkisi yok. Atomic Access'i anlamak için java öğreticisini okumanızı ve neden atomik erişimi kullandığınızı, ne araya girdiğini anladığınızı , cevabı bulacaksınız.
Basit bir ifadeyle,
static : static
değişkenler, herhangi bir nesne ile değil sınıfla ilişkilendirilir . Sınıfın her örneği, bellekte sabit bir konumda bulunan bir sınıf değişkenini paylaşır
Uçucu : Bu anahtar kelime hem uygulanabilir sınıf ve örnek değişkenleri.
Uçucu değişkenlerin kullanılması, bellek tutarlılığı hataları riskini azaltır, çünkü uçucu bir değişkene herhangi bir yazma işlemi, aynı değişkenin sonraki okumalarıyla önceden gerçekleşen bir ilişki kurar. Bu, değişken bir değişkende yapılan değişikliklerin her zaman diğer iş parçacıkları tarafından görülebilir olduğu anlamına gelir
Bu göz at maddeye göre Javin Paul
daha iyi bir şekilde uçucu değişkenleri anlamak için.
volatile
Anahtar kelime bulunmadığında, her bir iş parçacığının yığındaki değişkenin değeri farklı olabilir. Değişkeni şu şekilde yaparak volatile
, tüm iş parçacıkları çalışma belleğinde aynı değeri alır ve bellek tutarlılığı hataları önlenir.
Burada terim variable
ya static
(class) değişken ya da instance
(object) değişken olabilir.
Sorgunuzla ilgili olarak:
Her neyse, statik değişken değeri de tüm iş parçacıkları için bir değer olacak, o zaman neden değişkenliğe gidelim?
instance
Uygulamamda değişken gerekiyorsa değişken kullanamıyorum static
. static
Değişken durumunda bile , şemada gösterildiği gibi İş parçacığı önbelleği nedeniyle tutarlılık garanti edilmez.
volatile
Değişkenlerin kullanılması bellek tutarlılığı hataları riskini azaltır, çünkü uçucu bir değişkene yapılan herhangi bir yazma aynı değişkenin sonraki okumalarıyla daha önce gerçekleşen bir ilişki kurar. Bu, değişken bir değişkende yapılan değişikliklerin her zaman diğer iş parçacıkları tarafından görülebilir olduğu anlamına gelir.
Dahası, bir iş parçacığı değişken bir değişkeni okuduğunda, yalnızca değişkendeki en son değişikliği değil, aynı zamanda değişime neden olan kodun yan etkilerinin de değişebileceğini gösterir. . Yan etkileri önlemek için senkronize değişkenler kullanmanız gerekir. Ancak java'da daha iyi bir çözüm var.
Basit atomik değişken erişiminin kullanılması, bu değişkenlere senkronize kod ile erişmekten daha etkilidir
java.util.concurrent
Paketteki bazı sınıflar senkronizasyona dayanmayan atomik yöntemler sağlar.
Daha fazla ayrıntı için bu üst düzey eşzamanlılık kontrol makalesine bakın.
Özellikle Atomik değişkenlere bir göz atın .
İlgili SE soruları:
volatile
benim için cevap açıklık getirmektedir çok hala neden kullanmam gerekiyor, daha önce ama volatile
ile static
değişken.
değişken değişken değer erişimi doğrudan ana bellekten olacaktır. Sadece çok iş parçacıklı ortamda kullanılmalıdır. statik değişken bir kez yüklenecektir. Tek bir iş parçacığı ortamında kullanılırsa, değişkenin kopyası güncellense bile ve tek bir iş parçacığı olduğundan ona erişmenin bir zararı olmaz.
Statik değişken çoklu iş parçacığı ortamında kullanılırsa, bundan istenen sonuç beklenirse sorunlar olacaktır. Her iş parçacığının kendi kopyası olduğundan, bir iş parçacığından statik değişken üzerindeki herhangi bir artış veya azalma başka bir iş parçacığına yansımayabilir.
statik değişkenden istenen sonuçlar beklenirse çoklu iş parçacığında statik ile uçucu kullanın, sonra her şey çözülecektir.
Statik değişkenlerin iş parçacığı yerel belleğinde önbelleğe alındığından ya da DEĞİL olduğundan emin olun. Ancak aynı nesneye (obj) erişen iki iş parçacığı (T1, T2) yürüttüğümde ve T1 iş parçacığı tarafından statik değişkene yapılan güncelleştirme T2'ye yansıdı.
Bir değişkeni statik olarak bildirirsek, değişkenin yalnızca bir kopyası olacaktır. Bu nedenle, farklı iş parçacıkları bu değişkene her eriştiğinde, değişken için yalnızca bir son değer olacaktır (çünkü değişken için yalnızca bir bellek konumu vardır).
Değişken geçici olarak bildirilirse, tüm evrelerin değişkenin kendi kopyaları olur ancak değer ana bellekten alınır. Bu nedenle, tüm evrelerdeki değişkenin değeri aynı olacaktır.
Yani, her iki durumda da, asıl nokta, değişkenin değerinin tüm iş parçacıkları arasında aynı olmasıdır.