Apakah metode statis yang tidak disinkronkan thread aman jika mereka tidak mengubah variabel kelas statis?

145

Saya bertanya-tanya apakah Anda memiliki metode statis yang tidak disinkronkan, tetapi tidak mengubah variabel statis apakah aman? Bagaimana jika metode ini membuat variabel lokal di dalamnya? Misalnya, apakah kode berikut ini aman untuk digunakan?

public static String[] makeStringArray( String a, String b ){
    return new String[]{ a, b };
}

Jadi jika saya memiliki dua utas yang memanggil metode ini secara terus-menerus dan bersamaan, satu dengan anjing (katakanlah "dane besar" dan "anjing jantan") dan yang lainnya dengan kucing (katakanlah "persia" dan "siam") apakah saya akan mendapatkan kucing dan anjing dalam array yang sama? Atau akankah kucing dan anjing tidak pernah berada di dalam doa yang sama dengan metode ini pada saat yang sama?

Kereta luncur
sumber
utas lain tentang masalah ini: stackoverflow.com/questions/8015797/…
象 嘉 道
2
Itu adalah pertanyaan yang berbeda, ini adalah apakah pemanggilan metode statis aman, bukan apakah array.
Kereta luncur

Jawaban:

212

Metode ini 100% aman, bahkan jika tidak static. Masalah dengan keamanan ulir muncul ketika Anda perlu berbagi data di antara utas - Anda harus menjaga atomicity, visibilitas, dll.

Metode ini hanya beroperasi pada parameter, yang berada di stack dan referensi ke objek yang tidak dapat diubah pada heap. Stack secara inheren bersifat lokal untuk utas , jadi tidak ada pembagian data yang terjadi.

Objek yang Stringtidak dapat diubah ( dalam hal ini) juga aman dari thread karena sekali dibuat mereka tidak dapat diubah dan semua utas melihat nilai yang sama. Di sisi lain jika metode itu menerima (bisa berubah) DateAnda bisa memiliki masalah. Dua utas secara bersamaan dapat memodifikasi instance objek yang sama, yang menyebabkan kondisi balapan dan masalah visibilitas.

Tomasz Nurkiewicz
sumber
4
Jawaban yang benar. Variabel tingkat metode direplikasi di setiap tumpukan eksekusi ulir.
Sid
secara teknis metode ini harus diuraikan dan parameternya adalah register CPU. Meskipun demikian, jawabannya benar
bestsss
43
Tumpukan ini tentu saja lokal untuk utas saat ini, tetapi Anda dapat memiliki referensi ke objek bersama pada tumpukan itu. Ini bukan masalah dalam contoh karena String tidak dapat diubah, tetapi metode yang mengubah parameter yang diteruskan dapat memiliki masalah keamanan utas jika objek yang diteruskan ini dapat diakses dari banyak utas.
Jörn Horstmann
1
Seperti @TomaszNurkiewicz sebutkan, jika kita melewati referensi objek yang bisa berubah, kita bisa masuk ke kondisi balapan. Apakah ini berlaku bahkan jika metode tidak mengubah objek dengan cara apa pun? Maksud saya, apakah masih diklasifikasikan sebagai kondisi balapan karena objeknya bisa berubah? Dan bagaimana jika kita menambahkan kata kunci terakhir ke parameter?
Rafay
Bagaimana jika saya melewatkan objek kelas dalam metode ini? Akankah varaible di stack atau heap?
grep
28

Suatu metode hanya bisa tidak aman ketika ia mengubah beberapa status bersama. Apakah itu statis atau tidak tidak relevan.

Konrad Garus
sumber
3
@Konrad_Garus Pertanyaan di sini adalah di sepanjang baris apakah variabel lokal merupakan keadaan bersama atau tidak, atau apakah tumpukan untuk metode statis per thread atau dibagikan.
Kereta luncur
"Sebuah metode hanya bisa tidak aman ketika ia mengubah beberapa status bersama." Tidak, ini juga dapat menjadi utas yang tidak aman jika hanya mengakses status bersama tanpa mengubahnya. Akses yang tidak disinkronkan ke objek yang dapat diubah dapat mengakses status tidak konsisten jika objek dimutasi oleh utas lainnya, bahkan jika utas lainnya disinkronkan dengan benar. Kedua thread perlu sinkronisasi yang tepat untuk menjaga keselamatan thread.
Warren Dew
12

Fungsi ini sangat aman untuk thread.

Jika Anda memikirkannya ... anggap apa yang akan terjadi jika ini berbeda. Setiap fungsi yang biasa akan memiliki masalah threading jika tidak disinkronkan, sehingga semua fungsi API di JDK harus disinkronkan, karena mereka berpotensi dipanggil oleh banyak utas. Dan karena sebagian besar waktu aplikasi menggunakan beberapa API, aplikasi multithreaded secara efektif tidak mungkin.

Ini terlalu konyol untuk dipikirkan, jadi hanya untuk Anda: Metode tidak aman jika ada alasan yang jelas mengapa mungkin ada masalah. Cobalah untuk selalu berpikir tentang bagaimana jika ada beberapa utas dalam fungsi saya, dan bagaimana jika Anda memiliki langkah-debugger dan akan satu langkah demi langkah maju yang pertama ... lalu utas kedua ... mungkin yang kedua lagi ... apakah akan ada masalah? Jika Anda menemukannya, itu tidak aman.

Perlu diketahui juga, bahwa sebagian besar kelas Java 1.5 Collection bukan threadsafe, kecuali yang dinyatakan, seperti ConcurrentHashMap.

Dan jika Anda benar-benar ingin menyelami ini, perhatikan dengan cermat kata kunci yang mudah menguap dan SEMUA efek sampingnya. Lihatlah kelas Semaphore () dan Lock (), dan teman-teman mereka di java.util.Concurrent. Baca semua dokumen API di sekitar kelas. Layak untuk belajar dan memuaskan juga.

Maaf atas jawaban yang terlalu rumit ini.

Daniel
sumber
2
"Jika Anda memikirkannya ... asumsikan apa yang akan terjadi jika ini berbeda. Setiap fungsi biasa akan memiliki masalah threading jika tidak disinkronkan, sehingga semua fungsi API di JDK harus disinkronkan, karena mereka berpotensi dipanggil oleh banyak utas. " Poin bagus!
Kereta luncur
1

Gunakan statickata kunci dengan metode statis tersinkronisasi untuk memodifikasi data statis yang dibagi di antara utas. Dengan statickata kunci, semua utas yang dibuat akan bersaing untuk satu versi metode ini.

Gunakan volatilekata kunci bersama dengan metode instance yang disinkronkan akan menjamin bahwa setiap utas memiliki salinan sendiri dari data bersama dan tidak ada baca / tulis akan bocor di antara utas.

clinton
sumber
0

Objek string menjadi tidak berubah adalah alasan lain untuk skenario thread-safe di atas. Alih-alih jika objek yang dapat diubah digunakan (misalkan makeMutableArray ..) maka pasti thread-safety akan rusak.

keras
sumber
Pertanyaannya adalah apakah panggilan metode statis akan pernah melihat argumen panggilan lain ke metode yang sama dari utas lainnya. Jawabannya adalah "tidak!" Ini, saya tahu tetapi ingin bisa membuktikan kepada rekan kerja yang meragukan.
Kereta luncur
Mengapa tanggapan ini tidak dipilih? Intinya, tidak dikontribusikan oleh jawaban lain, adalah bahwa sifat berubah-ubah mungkin ada di dalam atau di luar. Jika Anda mengembalikan yang bisa diubah, maka Anda tidak menggunakan threadsafe. Pertanyaan tidak mengajukan pertanyaannya sesempit komentar yang disarankan; pertanyaan yang diperluas setelah sampel kode dapat dinyatakan dalam kode, mungkin sebagai unit test. Tapi saya bersimpati dengan mencoba meyakinkan rekan kerja. "Mereka tidak percaya padaku, atau kode tesku, atau Josh Bloch, tapi mungkin mereka akan menerima jawaban pada SO."
som-snytt