Yerel değişkenler Java'da neden güvenlidir?


91

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.


27
Çünkü Stack içinde tahsis edilmişlerdir. Ve iplikler yığını paylaşmazlar .. her biri için benzersizdir ..
Rohit Jain

Yanıtlar:


103

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 .


13
Üzgünüm, yanılıyorsunuz, sadece ilkel yerel değişkenler yığın üzerinde saklanıyor. Rest tüm değişkenler Heap üzerinde saklanır. Yığınında bunu tahsis olabilecek bazı varibles için Java'nın 7 tanıtıldı kaçış analizi,
Jatin

6
Yığın, yalnızca öbek üzerindeki nesnenin başvurusunu tutar. Yığın temizlendiği için referans da temizlenir. dolayısıyla çöp toplama için kullanılabilir
Jatin

6
@Jatin: Haklısın. Hafızayı kastettiğimde, nesneler için referans değeri ve ilkellerin değerleri için (acemi geliştiricilerin de Nesnelerin yığın üzerinde olduğunu bildiklerini düşünüyorum).
kosa

2
@Nambari ancak referans değeri paylaşılan bir değişkeni gösteriyorsa. O halde ipliğin güvenli olduğunu nasıl söyleyebiliriz?
H.Rabiee

3
@hajder: Bir değişkeni paylaşımlı yapan nedir? oradan başlayın. Ya örnek ya da sınıf değişkenleri doğru mu? yerel değişkenler değil VE bu konudaki Marko Toplink cevabını okuyun, bence kafanızın karıştığı nokta bu.
kosa

19

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.


Belgede bir hata var, lütfen @Nambari yanıtının yorumlarına bakın
Jatin

LocalSafeInt'in her zaman sadece 0, sonra 1 olacağı ve sonra silineceği gerçeğine işaret ediyorsanız, bu iyi. Bu, bu değişkenin iş parçacıkları arasında paylaşılmadığını ve dolayısıyla çoklu iş parçacığından etkilenmediğini gösteriyor. Sanırım iş parçacığı güvenliğinin her zaman sadece 0 veya 1 olduğunu biraz daha
belirtelim

14

İş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ığı NotThreadsafeaynı 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ığı Threadsafetamamen farklı değişkenler görecek ve birbirlerini etkileyemeyecek.


6

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.


1
"Başvurduğu nesnede yöntemleri çağırmak, doğası gereği iş parçacığı güvenli değildir" diyorsunuz. Ancak, bir yöntem yerel başvurusu tarafından başvurulan nesne - bu yöntem kapsamında somutlaştırılmış - iki iş parçacığı tarafından nasıl paylaşılabilir? Örnek olarak belirtebilir misin?
Akshay Lokur

1
Yerel bir değişken, sorunun parçası olmayan yöntem kapsamında somutlaştırılmış bir nesneyi tutabilir veya tutmayabilir. Öyle olsa bile, yöntem paylaşılan duruma erişebilir.
Marko Topolnik

6

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 itüm dişlerin sonunda değerinin olması garanti edilmez 100.


Merhaba Weston, Yukarıdaki tartışmadan ve aşağıdaki cevaplardan, java'nın tüm yerel değişkenler için iş parçacığı güvenliği sağladığını anladım. O halde senkronize anahtar kelimenin gerçek kullanımının ne olduğunu öğrenebilir miyim? lütfen bunun gibi bir örnekle açıklar mısınız?
Prabhu

5

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.


3

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.


1

İş 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 stackve 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;
}

görüntü açıklamasını buraya girin

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.