Java'da multi-threading okuyordum ve bununla karşılaştım
Yerel değişkenler Java'da iş parçacığı açısından güvenlidir.
O zamandan beri yerel değişkenlerin Nasıl / Neden güvenli olduğunu düşünüyordum.
Lütfen birisi bana haber versin.
Java'da multi-threading okuyordum ve bununla karşılaştım
Yerel değişkenler Java'da iş parçacığı açısından güvenlidir.
O zamandan beri yerel değişkenlerin Nasıl / Neden güvenli olduğunu düşünüyordum.
Lütfen birisi bana haber versin.
Yanıtlar:
Bir iş parçacığı oluşturduğunuzda, kendi yığını da oluşturulur. İki iş parçacığının iki yığını olacaktır ve bir iş parçacığı, yığınını asla diğer iş parçacığı ile paylaşmaz.
Programınızda tanımlanan tüm yerel değişkenler, yığın halinde bellek tahsis edilecektir (Jatin'in yorumladığı gibi, burada bellek, nesneler için referans değeri ve ilkel türler için değer anlamına gelir) (Bir evre tarafından yapılan her yöntem çağrısı, kendi yığınında bir yığın çerçevesi oluşturur). Yöntem yürütme bu iş parçacığı tarafından tamamlanır tamamlanmaz, yığın çerçevesi kaldırılacaktır.
Youtube'da Stanford profesörü tarafından bu kavramı anlamanıza yardımcı olabilecek harika bir ders var .
Yerel değişkenler her iş parçacığının kendi yığınında saklanır. Bu, yerel değişkenlerin hiçbir zaman evreler arasında paylaşılmadığı anlamına gelir. Bu aynı zamanda tüm yerel ilkel değişkenlerin iş parçacığı açısından güvenli olduğu anlamına gelir.
public void someMethod(){
long threadSafeInt = 0;
threadSafeInt++;
}
Nesnelere yerel referanslar biraz farklıdır. Referansın kendisi paylaşılmaz. Bununla birlikte, başvurulan nesne, her evrenin yerel yığınında depolanmaz. Tüm nesneler paylaşılan yığın içinde saklanır. Yerel olarak oluşturulan bir nesne, içinde oluşturulduğu yöntemden asla kaçmazsa, iş parçacığı güvenlidir. Aslında, bu yöntemlerden veya nesnelerden hiçbiri aktarılan nesneyi diğer iş parçacıkları için kullanılabilir hale getirmediği sürece, onu diğer yöntemlere ve nesnelere de aktarabilirsiniz.
İşlevsellik tanımları gibi yöntemleri düşünün. İki iş parçacığı aynı yöntemi çalıştırdığında, bunlar hiçbir şekilde ilişkili değildir. Her biri her yerel değişkenin kendi versiyonunu yaratacak ve birbirleriyle hiçbir şekilde etkileşim kuramayacaklar.
Değişkenler yerel değilse (sınıf düzeyinde bir yöntemin dışında tanımlanan örnek değişkenleri gibi), bunlar örneğe eklenir (yöntemin tek bir çalıştırmasına değil). Bu durumda, aynı yöntemi çalıştıran iki iş parçacığı tek bir değişkeni görür ve bu iş parçacığı için güvenli değildir.
Şu iki durumu düşünün:
public class NotThreadsafe {
int x = 0;
public int incrementX() {
x++;
return x;
}
}
public class Threadsafe {
public int getTwoTimesTwo() {
int x = 1;
x++;
return x*x;
}
}
İlkinde, aynı oluşum üzerinde çalışan iki iş parçacığı NotThreadsafe
aynı x'i görecektir. Bu tehlikeli olabilir, çünkü iş parçacıkları x'i değiştirmeye çalışıyor! İkincisi, aynı örnek üzerinde çalışan iki iş parçacığı Threadsafe
tamamen farklı değişkenler görecek ve birbirlerini etkileyemeyecek.
Her yöntem çağrısının kendi yerel değişkenleri vardır ve açık bir şekilde, bir yöntem çağrısı tek bir iş parçacığında gerçekleşir. Yalnızca tek bir iş parçacığı tarafından güncellenen bir değişken, doğası gereği iş parçacığı açısından güvenlidir.
Bununla birlikte , bunun tam olarak ne anlama geldiğine dikkat edin: yalnızca değişkenin kendisine yazılanlar iş parçacığı açısından güvenlidir; başvurduğu nesnede yöntemleri çağırmak , doğası gereği iş parçacığı açısından güvenli değildir . Aynı şey, nesnenin değişkenlerini doğrudan güncellemek için de geçerlidir.
Nambari'ninki gibi diğer cevaplara ek olarak.
Anoymous bir tür yönteminde yerel bir değişken kullanabileceğinizi belirtmek isterim:
Bu yöntem, iş parçacığı güvenliğini tehlikeye atabilecek diğer evrelerde çağrılabilir, bu nedenle java, anoymous türlerde kullanılan tüm yerel değişkenleri nihai olarak bildirilmeye zorlar.
Şu yasadışı kodu düşünün:
public void nonCompilableMethod() {
int i=0;
for(int t=0; t<100; t++)
{
new Thread(new Runnable() {
public void run() {
i++; //compile error, i must be final:
//Cannot refer to a non-final variable i inside an
//inner class defined in a different method
}
}).start();
}
}
Java buna izin verdiyse (C # 'nin "kapatmalar" yoluyla yaptığı gibi), yerel bir değişken artık her koşulda iş parçacığı güvenli olmayacaktır. Bu durumda i
tüm dişlerin sonunda değerinin olması garanti edilmez 100
.
Konu kendi yığınına sahip olacaktır. İki iş parçacığının iki yığını olacaktır ve bir iş parçacığı, yığınını asla diğer iş parçacığı ile paylaşmaz. Yerel değişkenler her iş parçacığının kendi yığınında saklanır. Bu, yerel değişkenlerin hiçbir zaman evreler arasında paylaşılmadığı anlamına gelir.
Temelde Java'da Sınıf Bilgilerini ve verilerini depolamak için Dört Depolama Türü Vardır:
Yöntem Alanı, Yığın, JAVA Yığını, PC
bu nedenle Yöntem alanı ve Yığın tüm iş parçacıkları tarafından paylaşılır, ancak her iş parçacığının kendi JAVA Yığını ve PC'si vardır ve bu, herhangi bir İş Parçacığı tarafından paylaşılmaz.
Java'daki her yöntem Stack frame gibidir. Bu nedenle, bir yöntem bir iş parçacığı tarafından çağrıldığında, yığın çerçevesi JAVA Yığına yüklenir. Bu yığın çerçevesinde ve ilgili işlenen yığınında bulunan tüm yerel değişken başkaları tarafından paylaşılmaz. PC, yöntemin bayt kodunda yürütülecek bir sonraki talimatın bilgisine sahip olacaktır. bu nedenle tüm yerel değişkenler İPLİK GÜVENLİDİR.
@Weston da iyi bir cevap verdi.
İş parçacığı yığınında yalnızca yerel değişkenler saklanır.
Yerel değişken olduğu primitive type
(örneğin int, uzun ...) depolanır thread stack
ve sonuç olarak - diğer iplik buna bir erişimi yok.
Yerel değişken olduğunu reference type
(ardıl arasında Object
) 2 kısım ihtiva - (depolanır adresi thread stack
(depolanır) ve nesneyi heap
)
class MyRunnable implements Runnable() {
public void run() {
method1();
}
void method1() {
int intPrimitive = 1;
method2();
}
void method2() {
MyObject1 myObject1 = new MyObject1();
}
}
class MyObject1 {
MyObject2 myObject2 = new MyObject2();
}
class MyObject2 {
MyObject3 myObject3 = MyObject3.shared;
}
class MyObject3 {
static MyObject3 shared = new MyObject3();
boolean b = false;
}