Perilaku metode statis di lingkungan multi-threaded di java

114

Ada pertanyaan bodoh sederhana yang mengganggu saya dan membuat beberapa argumen di benak saya. Saya ingin membuang semua keraguan tentang pertanyaan di bawah ini.

class Clstest{

    public static String testStaticMethod(String inFileStr) {

        // section 0

        // section 1

        // do something with inFileStr

        // section 2

        // section 3

        return inFileStr;

    }

}

Mari kita asumsikan ada lima utas yang masing-masing menjalankan panggilan ke Clstest.testStaticMethod("arg-n")pada saat yang sama.

Utas 1 panggilan Clstest.testStaticMethod("arg-1").

Saat utas 1 ada di bagian 1, utas 2 memanggil Clstest.testStaticMethod("arg-2").

Lalu apa yang akan terjadi pada Thread 1? Apakah akan masuk ke status tidur?

Ketika Thread 1 mendapat kesempatan, apakah ia akan melanjutkan eksekusi dari bagian 1 di mana ia dijeda?

Bagaimana itu terjadi ketika ada satu Clstest.testStaticMethoddan sama Clstest.testStaticMethoddibagikan di antara kelima utas?

Apakah ada kemungkinan untuk menukar yang inFileStrdikirim oleh beberapa utas?

namalfernandolk.dll
sumber
Bahasa apa yang Anda targetkan?
ΩmegaMan
3
@ OmegaMan: ini adalah java
namalfernandolk

Jawaban:

192

Jawaban Hans Passant bagus. Tetapi saya pikir saya akan mencoba dan menjelaskan pada tingkat yang sedikit lebih sederhana untuk siapa saja yang menemukan ini dan masih baru mengenal Java. Ini dia ..

Memori di java dibagi menjadi dua jenis - heap dan stack. Heap adalah tempat semua objek berada dan stack adalah tempat utas melakukan tugasnya. Setiap utas memiliki tumpukannya sendiri dan tidak dapat mengakses tumpukan satu sama lain. Setiap utas juga memiliki penunjuk ke kode yang menunjuk ke sedikit kode yang sedang mereka jalankan.

Saat utas mulai menjalankan metode baru, utas akan menyimpan argumen dan variabel lokal dalam metode itu di tumpukannya sendiri. Beberapa dari nilai ini mungkin menjadi petunjuk ke objek di heap. Jika dua utas menjalankan metode yang sama pada saat yang sama, keduanya akan memiliki penunjuk kode yang menunjuk ke metode itu dan memiliki salinan argumen dan variabel lokal sendiri di tumpukannya. Mereka hanya akan mengganggu satu sama lain jika benda-benda di tumpukannya mengarah ke benda yang sama di tumpukan. Dalam hal ini segala macam hal mungkin terjadi. Namun seperti yang ditunjukkan Hans, String tidak dapat diubah (tidak dapat diubah) jadi kami aman jika ini adalah satu-satunya objek yang "dibagikan".

Begitu banyak utas dapat menjalankan metode yang sama. Mereka mungkin tidak berjalan pada saat yang sama - tergantung berapa banyak core yang Anda miliki di mesin Anda saat JVM memetakan utas Java ke utas OS, yang dijadwalkan ke utas perangkat keras. Oleh karena itu, Anda memiliki sedikit kendali atas cara utas ini menyisipkan tanpa menggunakan mekanisme sinkronisasi yang rumit .

Perhatikan bahwa tidur adalah sesuatu yang dilakukan utas pada dirinya sendiri.

selig
sumber
3
Jadi, dalam lingkungan prosesor multi-core mungkin ada beberapa utas yang menjalankan kode yang sama pada waktu yang sama bukan? Dan dalam lingkungan prosesor tunggal, hanya ada satu utas yang berjalan pada waktu tertentu. (beberapa utas berbagi waktu di antara mereka.) Jadi, ketika utas penjadwalan memberikan kesempatan dari utas ekskusi saat ini (A) ke utas (B), bagaimana utas (A) melanjutkan dari tempat jeda? Maksud saya, bagaimana cara mengetahui poin resume? Apakah karena "Setiap utas juga memiliki penunjuk ke kode yang menunjuk ke sedikit kode yang sedang mereka jalankan?" seperti yang Anda katakan?
namalfernandolk
6
Anda mengerti. Hanya untuk memperjelas beberapa poin - pertama, bagaimana utas dijadwalkan berada di luar kendali Java. Saya berbicara tentang Sun's Hotspot JVM di sini. JVM memetakan utas Java ke utas OS dan OS memutuskan utas mana yang akan dijalankan. Seperti yang Anda katakan, pada mesin inti tunggal, OS hanya dapat berjalan satu per satu, tetapi dalam mesin multi inti, OS dapat berjalan lebih dari satu sekaligus. Kedua, utas tidak benar-benar sadar ketika dijeda, satu-satunya informasi yang dimilikinya adalah penunjuk program (penunjuk ke dalam kode) dan tumpukan, yang disimpan dan dipulihkan persis seperti semula.
selig
Jadi, inter-thread interferensi terjadi ketika thread menggunakan variabel di luar cakupan lokalnya dan, misalnya, satu thread memperbarui nilai variabel sebelum thread lain menarik variabel itu (atau pointer ke variabel) pada tumpukannya sendiri? Apakah itu pemahaman yang benar?
hariszhr
2
Untuk lebih tepatnya ... interferensi hanya dapat terjadi dan mungkin terjadi tetapi tidak akan selalu terjadi ... saat thread berbagi sesuatu di heap (non-lokal). Ada beberapa cara terjadinya interferensi yang bergantung pada dependensi di antara berbagai bagian kode. Saya tidak yakin tentang contoh Anda karena ada beberapa detail yang hilang. Mungkin Anda mengacu pada potensi masalah di mana utas A dan B membaca nilai bersama dan kemudian memperbaruinya berdasarkan nilai baca. Ini adalah perlombaan data.
selig
1
@selig jika saya memiliki kelas dengan hanya metode contoh misalnya: kelas layanan dan Ini tunggal maka saya tidak perlu khawatir tentang beberapa utas yang mengeksekusi metode contoh pada satu waktu karena kelas layanan tidak memiliki status di mana negara hanya ada jika kelas memiliki variabel instan. Apakah pemahaman saya benar?
Yug Singh
67

Apakah akan masuk ke status tidur?

Tidak, menjalankan utas tidak memengaruhi utas lain selama tidak disinkronkan dengan sengaja. Jika Anda memiliki lebih dari satu inti prosesor, semua mesin baru memilikinya, utas tersebut kemungkinan besar akan dieksekusi pada waktu yang sama. Itu menjadi sedikit lebih kecil kemungkinannya ketika Anda memulai 5 utas karena mesin Anda mungkin tidak memiliki cukup inti. Sistem operasi dipaksa untuk memilih di antara mereka, memberi mereka waktu masing-masing untuk dijalankan. Pekerjaan penjadwal utas. Sebuah utas tidak akan berada dalam status "tidur", itu hanya dijeda dan menunggu penjadwal utas memberikan kesempatan untuk berjalan. Ini akan melanjutkan di mana itu diinterupsi oleh penjadwal.

Apakah ada kemungkinan untuk menukar inFileStr yang dikirim oleh beberapa utas?

Tidak ada kemungkinan seperti itu, utas memiliki tumpukannya sendiri sehingga setiap argumen metode dan variabel lokal akan unik untuk setiap utas. Menggunakan string selanjutnya menjamin bahwa utas ini tidak dapat saling mengganggu karena string tidak dapat diubah.

Tidak ada jaminan seperti itu jika argumennya adalah referensi ke jenis objek yang bisa berubah lainnya. Atau jika metode itu sendiri menggunakan variabel yang statis atau referensi ke objek di heap. Sinkronisasi diperlukan ketika sebuah thread mengubah objek dan thread lain membacanya. Kata kunci kunci dalam bahasa C # adalah cara boilerplate untuk mengimplementasikan sinkronisasi yang diperlukan tersebut. Fakta bahwa metode ini statis tidak berarti sinkronisasi semacam itu tidak pernah diperlukan. Kemungkinannya kecil karena Anda tidak perlu khawatir tentang utas yang mengakses objek yang sama (membagikan ini ).

Hans Passant
sumber
3
Ups, tidak pernah melihat tag [java]. Cukup dekat.
Hans Passant
Saya lupa menambahkan ketika itu diposting. Salahku. :). Bagaimanapun terima kasih atas jawabannya. Itu sangat membantu.
namalfernandolk