Mengapa thread variabel lokal aman di Java

91

Saya membaca multi-threading di Java dan saya menemukan ini

Variabel lokal thread safe di Java.

Sejak itu saya telah memikirkan Bagaimana / Mengapa variabel lokal aman untuk thread.

Adakah yang bisa memberi tahu saya.

Anand
sumber
27
Karena mereka dialokasikan di Stack. Dan utas tidak berbagi tumpukan .. unik untuk masing-masing ..
Rohit Jain

Jawaban:

103

Saat Anda membuat utas, tumpukannya akan dibuat sendiri. Dua utas akan memiliki dua tumpukan dan satu utas tidak pernah berbagi tumpukannya dengan utas lainnya.

Semua variabel lokal yang ditentukan dalam program Anda akan dialokasikan memori dalam tumpukan (Seperti yang dikomentari Jatin, memori di sini berarti, nilai referensi untuk objek dan nilai untuk tipe primitif) (Setiap metode yang dipanggil oleh utas membuat bingkai tumpukan pada tumpukannya sendiri). Segera setelah eksekusi metode diselesaikan oleh utas ini, bingkai tumpukan akan dihapus.

Ada kuliah bagus dari profesor Stanford di youtube yang dapat membantu Anda memahami konsep ini.

kosa
sumber
13
Maaf, Anda salah, hanya variabel lokal primitif yang disimpan di stack. Selebihnya semua variabel disimpan di Heap. Java 7 memperkenalkan analisis pelolosan, yang untuk beberapa variabel mungkin mengalokasikannya dalam tumpukan
Jatin
6
Stack hanya menyimpan referensi ke objek di heap. Karena tumpukan dihapus, begitu pula referensinya. karenanya tersedia untuk pengumpulan sampah
Jatin
6
@ Jatin: Anda benar. Yang saya maksud adalah memori, yang saya maksud adalah nilai referensi untuk objek dan nilai untuk primitif (saya pikir pengembang pemula juga tahu bahwa Objek berada di tumpukan).
kosa
2
@Nambari tetapi jika nilai referensi mengarah ke variabel bersama. Lalu bagaimana kita bisa mengatakan bahwa ini aman untuk benang?
H.Rabiee
3
@hajder: Apa yang membuat variabel sebagai dibagikan? mulai dari situ. Entah variabel instance atau kelas kan? bukan variabel lokal DAN baca jawaban Marko Toplink di utas ini, saya pikir itu adalah poin yang membuat Anda bingung.
kosa
19

Variabel lokal disimpan di tumpukan masing-masing utas. Itu berarti variabel lokal tidak pernah dibagikan antar utas. Itu juga berarti bahwa semua variabel primitif lokal aman untuk thread.

public void someMethod(){

   long threadSafeInt = 0;

   threadSafeInt++;
}

Referensi lokal ke objek sedikit berbeda. Referensi itu sendiri tidak dibagikan. Namun, objek yang direferensikan tidak disimpan di tumpukan lokal setiap utas. Semua objek disimpan di heap bersama. Jika sebuah objek yang dibuat secara lokal tidak pernah lolos dari metode pembuatannya, itu adalah thread aman. Bahkan Anda juga bisa meneruskannya ke metode dan objek lain selama tidak ada metode atau objek ini yang membuat objek yang diteruskan tersedia untuk utas lain

Renjith
sumber
Ada kesalahan dalam agrument, silakan lihat komentar tanggapan @Nambari
Jatin
Jika Anda mengacu pada fakta bahwa localSafeInt selalu akan menjadi 0, kemudian 1 dan kemudian dihapus, itu bagus. Jadi ini menunjukkan bahwa variabel ini tidak dibagi di antara utas dan dengan demikian tidak terpengaruh oleh multi threading .. saya pikir Anda bisa menunjukkan sedikit lebih banyak bahwa threadsafe selalu hanya 0 atau 1
tObi
14

Pikirkan metode seperti definisi fungsionalitas. Ketika dua utas menjalankan metode yang sama, mereka sama sekali tidak terkait. Mereka masing-masing akan membuat versinya sendiri untuk setiap variabel lokal, dan tidak akan dapat berinteraksi satu sama lain dengan cara apa pun.

Jika variabel tidak lokal (seperti variabel instance yang ditentukan di luar metode di tingkat kelas), variabel tersebut akan dilampirkan ke instance (bukan ke satu proses metode). Dalam kasus ini, dua utas yang menjalankan metode yang sama melihat satu variabel, dan ini tidak aman untuk utas.

Pertimbangkan dua kasus ini:

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;
    }
}

Di bagian pertama, dua utas yang berjalan pada contoh yang sama NotThreadsafeakan melihat x yang sama. Ini bisa berbahaya, karena utas mencoba mengubah x! Yang kedua, dua utas yang berjalan pada contoh yang sama Threadsafeakan melihat variabel yang sangat berbeda, dan tidak dapat saling memengaruhi.

Cory Kendall
sumber
6

Setiap pemanggilan metode memiliki variabel lokalnya sendiri dan, jelas, pemanggilan metode terjadi dalam satu utas. Variabel yang hanya diperbarui dengan satu thread secara inheren aman untuk thread.

Namun , perhatikan baik-baik apa yang sebenarnya dimaksud dengan ini: hanya penulisan ke variabel itu sendiri yang aman untuk thread; memanggil metode pada objek yang dirujuk tidak secara inheren aman untuk thread . Hal yang sama berlaku untuk memperbarui variabel objek secara langsung.

Marko Topolnik
sumber
1
Anda mengatakan "metode pemanggil pada objek yang dirujuknya tidak inheren aman untuk thread". Tapi, bagaimana objek yang dirujuk oleh referensi lokal metode - yang dipakai dalam lingkup metode ini - dapat dibagi oleh dua utas? Bisakah Anda menunjukkan dengan contoh?
Akshay Lokur
1
Variabel lokal mungkin atau mungkin tidak menyimpan objek yang dipakai dalam lingkup metode, itu bukan bagian dari pertanyaan. Meskipun demikian, metode tersebut dapat mengakses status bersama.
Marko Topolnik
6

Selain jawaban lain seperti Nambari.

Saya ingin menunjukkan bahwa Anda dapat menggunakan variabel lokal dalam metode tipe anoymous:

Metode ini dapat dipanggil di thread lain yang dapat mengganggu keamanan thread, jadi java memaksa semua variabel lokal yang digunakan dalam tipe anoymous untuk dideklarasikan sebagai final.

Pertimbangkan kode ilegal ini:

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();
     }
  }

Jika java mengizinkan ini (seperti yang dilakukan C # melalui "closures"), variabel lokal tidak akan lagi menjadi threadsafe dalam semua keadaan. Dalam hal ini, nilai idi akhir semua utas tidak dijamin 100.

weston
sumber
Hai Weston, Dari diskusi di atas dan jawaban di bawah, saya mengerti bahwa java menjamin keamanan benang untuk semua variabel lokal. Bolehkah saya mengetahui apa sebenarnya penggunaan kata kunci tersinkronisasi? bisa tolong jelaskan dengan contoh seperti ini.
Prabhu
5

Thread akan memiliki tumpukannya sendiri. Dua utas akan memiliki dua tumpukan dan satu utas tidak pernah berbagi tumpukannya dengan utas lainnya. Variabel lokal disimpan di tumpukan masing-masing utas. Itu berarti variabel lokal tidak pernah dibagikan antar utas.

Sudhirkumar Murkute
sumber
3

Pada dasarnya Empat Jenis Penyimpanan Ada di java untuk menyimpan Informasi Kelas dan data:

Metode Area, Heap, JAVA Stack, PC

jadi Area metode dan Heap dibagikan oleh semua utas tetapi setiap utas memiliki JAVA Stack dan PC-nya sendiri dan itu tidak dibagikan oleh Thread lainnya.

Setiap metode di java adalah sebagai Stack frame. jadi, ketika satu metode dipanggil oleh thread yang stack frame dimuat pada JAVA Stack-nya. Semua variabel lokal yang ada di stack frame dan operan stack terkait tidak dibagikan oleh orang lain. PC akan memiliki informasi tentang instruksi selanjutnya untuk dieksekusi dalam kode byte metode. jadi semua variabel lokal AMAN.

@Weston juga memberikan jawaban yang bagus.

Prashant
sumber
1

Hanya variabel lokal yang disimpan di tumpukan benang.

Variabel lokal yang primitive type(misalnya int, long ...) disimpan di thread stackdan akibatnya - thread lain tidak memiliki akses ke sana.

Variabel lokal yaitu reference type(penerus Object) berisi dari 2 bagian - alamat (yang disimpan di thread stack) dan objek (yang disimpan di 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;
}

masukkan deskripsi gambar di sini

yoAlex5
sumber