Java'da Uçucu ve Statik


265

Bunun statictüm nesneler volatileiçin değerin bir kopyası ve tüm evreler için değerin bir kopyası anlamına geldiğini söylemek doğru mudur ?

Her neyse, staticdeğişken bir değer de tüm evreler için bir değer olacak, o zaman neden gitmeliyiz volatile?


Yanıtlar:


365

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ç Objectsoluş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, Objectalanlarla 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;
}

concurrentMethodWrongEş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 AtomicIntegersınıfı kullanın .


7
Uçucu değiştirici, bir alanı okuyan herhangi bir iş parçacığının en son yazılan değeri görmesini garanti eder, bu nedenle değişkenin birden fazla iş parçacığı arasında paylaşılması ve bu özelliğe ihtiyacınız olması gerekir, kullanım durumuna bağlıdır.
stivlo

5
"Yerel olarak önbelleğe alınmış" dediğinizde önbellek nedir? CPU önbellek, bir çeşit JVM önbellek?
mert inan

6
@mertinan evet, değişken işlemci veya çekirdeğe yakın bir önbellekte olabilir. Daha fazla bilgi için cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html adresine bakın.
stivlo

15
'uçucu' yok değildir 'nesnesi için bir değişken' anlamına gelmektedir. 'Statik' olmaması bunu yapar. OP'nin bu temel yanlış algısını gideremediği için -1.
Lorne Marquis

27
@EJP Cümlenin "Değişken olarak değişken olarak bildirilmesi, her bir Nesne için bir değişken olacağı düşünülüyordu. Bu yüzden yüzeyde normal bir değişkenten fark yok gibi görünüyor" diye açıklıyor, statik değil , ekledim , makaleyi düzenlemek ve daha net hale getirmek için ifadeleri geliştirmek için çekinmeyin.
stivlo

288

Statik ve Uçucu Arasındaki Fark:

Statik Değişken : İki konu (varsayalım ederse t1ve t2) aynı nesneyi erişmekte ve anlama ardından statik olarak bildirilmiş bir değişken güncelliyoruz t1ve t2kendi önbelleğinde (statik değişkenler dahil) aynı nesnenin kendi yerel kopyasını yapabilir, böylece güncelleme tarafından t1yerel ö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 t1ve 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 t1ve t2yapabilir . 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.


6
Merhaba @Som, Yanlışsam lütfen düzeltin. Ama "sen deyimi sanmıyorum statik değişkene bir dişin güncelleme (kendi yerel önbellekte) tüm dişler hemen değişiklikleri yansıtır nerede Konu bağlamında değil. " Değil bağlamda" olmalıdır Bir iş parçacığının statik değişkene güncelleştirilmesinin <<NOT>> öğesinin, tüm iş parçacıklarındaki değişiklikleri (yerel önbelleklerinde) hemen yansıtacağı iş parçacığı . "
Jaikrat

@Jaikrat Evet, bu benim için çok kafa karıştırıcıydı. Anladığım kadarıyla haklısın ve bu cevabın yazıldığı gibi yanlış olduğu. Yanılıyorsam da düzeltilmek istiyorum.
stuart

@Jaikrat Konular statik değişkenleri önbelleğe almaz, ancak güncellenmiş statik değişkenlere başvurur.
Som

@Som Daha sonra parayı düzeltmek ve Konu bağlamında kaldırmak istemezsiniz . Bu çok kafa karıştırıcı. Teşekkürler
Jaikrat

Ne yazık ki, bu cevap yanlış. Modern CPU'larda, bir volatiledeğ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.
David Schwartz

32

Diğer cevaplara ek olarak, bunun için bir resim eklemek istiyorum (pic anlaşılmasını kolaylaştırıyor)

resim açıklamasını buraya girin

staticdeğ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 .

volatilebildirimi, iş parçacıklarının verileri önbelleğe almamasını sağlar ve yalnızca paylaşılan kopyayı kullanır .

görüntü kaynağı


1
statik değişkenler bir iş parçacığı altında nesneler arasında paylaşılır? Bu, statik değişkenlerin evrelerden bağımsız olarak nesneler arasında paylaşıldığını okumalıdır.
cquezel

1
msgstr "uçucu değişkenler birden çok iş parçacığı arasında paylaşılıyor (nesneler de)." Uçucu, değişkenlerin birden çok iş parçacığı veya nesne arasında paylaşılma şeklini değiştirmez. Çalışma zamanının değeri önbelleğe alma iznini değiştirir.
cquezel

1
Statik değişkenler hakkındaki yorumunuz statik olmayanlar için de geçerlidir ve "önbelleğe alınacaktır" ve "yansıtmayacaktır" muhtemelen yeniden ifade edilmelidir "önbelleğe alınabilir" ve "yansıtmayabilir".
cquezel

4
Çok kafam karışmıştı. bu resim tüm sorularımı sildi!
vins

5

Bence staticve volatiletü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.


4

Basit bir ifadeyle,

  1. static : staticdeğ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

  2. 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.

resim açıklamasını buraya girin

volatileAnahtar 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 variableya 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?

instanceUygulamamda değişken gerekiyorsa değişken kullanamıyorum static. staticDeğişken durumunda bile , şemada gösterildiği gibi İş parçacığı önbelleği nedeniyle tutarlılık garanti edilmez.

volatileDeğ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.concurrentPaketteki 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ı:

Uçucu ve Atomik

Uçucu boolean vs AtomicBoolean

Java'da uçucu ve senkronize arasındaki fark


Bu cevabı gerçekten takdir ediyorum. Ben ne olduğunu biliyordu volatilebenim için cevap açıklık getirmektedir çok hala neden kullanmam gerekiyor, daha önce ama volatileile staticdeğişken.
Chaklader Asfak Arefe

uçucu: Bu anahtar kelime hem sınıf hem de örnek değişkenleri için geçerlidir. Yukarıda söylediğin ifade, sınıfa uygulanmasında yanlış. değişken için geçerli olan sadece iki anahtar kelime geçici ve geçicidir. bu yüzden uçucu sınıf için geçerli olmayacak.
ASR

uçucu sınıf (statik) değişkenlere uygulanabilir. Google'da çift kilitli singleton bağlantılarına göz atın ve anlayışınızın yanlış olduğunu görebilirsiniz. stackoverflow.com/questions/18093735/…
Ravindra babu

özel statik uçucu geçerli bir bildirimdir.
Ravindra babu

0

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.


0

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ı.


-2

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.


15
Değişken geçici olarak bildirilirse, tüm evrelerin değişkenin kendi kopyaları olur ancak değer ana bellekten alınır. => doğru. Böylece, tüm evrelerdeki değişkenin değeri aynı olacaktır. => yanlış, her evre aynı Nesne için aynı değeri kullanır, ancak her Nesnenin kendi kopyası olacaktır.
stivlo
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.