Jika saya memiliki 2 metode yang disinkronkan di kelas yang sama, tetapi masing-masing mengakses variabel yang berbeda, dapatkah 2 utas mengakses 2 metode tersebut pada waktu yang sama? Apakah kunci terjadi pada objek, atau apakah itu spesifik seperti variabel di dalam metode yang disinkronkan?
Contoh:
class X {
private int a;
private int b;
public synchronized void addA(){
a++;
}
public synchronized void addB(){
b++;
}
}
Bisakah 2 utas mengakses instance yang sama dari pertunjukan kelas X x.addA(
) dan x.addB()
pada saat yang sama?
synchronized (this)
blok di sekitar tubuh metode. Objek "ini" tidak menjadi terkunci, melainkan objek "ini" digunakan sebagai mutex dan tubuh dicegah dari mengeksekusi bersamaan dengan bagian kode lain yang juga disinkronkan pada "ini." Ini tidak berpengaruh pada bidang / metode lain dari "ini" yang tidak disinkronkan.a
danb
objek, misalnyaInteger
s, Anda menyinkronkan pada instance yang Anda ganti dengan objek yang berbeda saat menerapkan++
operator.Disinkronkan pada deklarasi metode adalah gula sintaksis untuk ini:
Pada metode statis itu adalah gula sintaksis untuk ini:
Saya pikir jika desainer Java tahu kemudian apa yang dipahami sekarang tentang sinkronisasi, mereka tidak akan menambahkan gula sintaksis, karena lebih sering mengarah pada implementasi konkurensi yang buruk.
sumber
Dari "Tutorial Java ™" pada metode yang disinkronkan :
Dari "Tutorial Java ™" pada blok yang disinkronkan :
(Penekanan milikku)
Misalkan Anda memiliki 2 variabel non-interleaving . Jadi, Anda ingin mengakses masing-masing dari utas yang berbeda secara bersamaan. Anda perlu menentukan kunci tidak pada kelas objek itu sendiri, tetapi pada kelas Object seperti di bawah ini (contoh dari link Oracle kedua):
sumber
Kunci yang diakses ada pada objek, bukan pada metode. Variabel mana yang diakses dalam metode ini tidak relevan.
Menambahkan "disinkronkan" ke metode berarti utas yang menjalankan kode harus mendapatkan kunci pada objek sebelum melanjutkan. Menambahkan "sinkronisasi statis" berarti utas yang menjalankan kode harus memperoleh kunci pada objek kelas sebelum melanjutkan. Atau Anda dapat membungkus kode dalam blok seperti ini:
sehingga Anda dapat menentukan objek yang kuncinya harus diperoleh.
Jika Anda ingin menghindari mengunci pada objek yang mengandung Anda dapat memilih antara:
sumber
Dari tautan dokumentasi oracle
Membuat metode yang disinkronkan memiliki dua efek:
Lihat halaman dokumentasi ini untuk memahami kunci intrinsik dan perilaku kunci.
Ini akan menjawab pertanyaan Anda: Pada objek yang sama x, Anda tidak dapat memanggil x.addA () dan x.addB () pada saat yang sama ketika salah satu eksekusi metode yang disinkronkan sedang berlangsung.
sumber
Jika Anda memiliki beberapa metode yang tidak disinkronkan dan sedang mengakses dan mengubah variabel instan. Dalam contoh Anda:
sejumlah utas dapat mengakses metode yang tidak disinkronkan ini pada saat yang sama ketika utas lain dalam metode yang disinkronkan dari objek yang sama dan dapat membuat perubahan pada variabel instan. Untuk misalnya: -
Anda perlu menghindari skenario bahwa metode yang tidak disinkronkan mengakses variabel instan dan mengubahnya jika tidak ada gunanya menggunakan metode yang disinkronkan.
Dalam skenario di bawah ini: -
Hanya satu utas yang dapat berupa metode addA atau addB tetapi pada saat yang sama sejumlah utas dapat memasukkan metode changeState. Tidak ada dua utas yang dapat memasukkan addA dan addB pada saat yang sama (karena penguncian tingkat Objek) tetapi pada saat yang sama sejumlah utas dapat masuk ke changeState.
sumber
Anda dapat melakukan sesuatu seperti berikut ini. Dalam hal ini Anda menggunakan kunci pada a dan b untuk menyinkronkan alih-alih kunci pada "ini". Kami tidak dapat menggunakan int karena nilai primitif tidak memiliki kunci, jadi kami menggunakan Integer.
sumber
Ya, itu akan memblokir metode lain karena metode yang disinkronkan berlaku untuk objek kelas WHOLE seperti yang ditunjukkan .... tapi bagaimanapun itu akan memblokir eksekusi utas lainnya SAJA sambil melakukan penjumlahan dalam metode apa pun, addA atau addB yang dimasukkan, karena ketika selesai ... satu utas akan GRATIS objek dan utas lainnya akan mengakses metode lainnya dan seterusnya berfungsi dengan baik.
Maksud saya "disinkronkan" dibuat tepat untuk memblokir utas lainnya dari mengakses yang lain saat dalam eksekusi kode tertentu. JADI AKHIRNYA KODE INI AKAN BEKERJA HALUS.
Sebagai catatan akhir, jika ada variabel 'a' dan 'b', bukan hanya variabel unik 'a' atau nama lain apa pun, tidak perlu menyinkronkan metode ini karena sangat aman mengakses var lain (Memori lain lokasi).
Akan bekerja juga
sumber
Contoh ini (meskipun tidak cantik) dapat memberikan lebih banyak wawasan tentang mekanisme penguncian. Jika incrementA yang disinkronkan , dan incrementB yang tidak disinkronkan , maka incrementB akan dieksekusi secepatnya, tetapi jika incrementB juga disinkronkan maka harus 'menunggu' untuk incrementA sampai akhir, sebelum incrementB dapat melakukan tugasnya.
Kedua metode dipanggil ke objek - instance tunggal, dalam contoh ini adalah: pekerjaan , dan utas 'bersaing' adalah aThread dan utama .
Coba dengan ' disinkronkan ' dalam kenaikan B dan tanpa itu dan Anda akan melihat hasil yang berbeda. Jika kenaikan B ' disinkronkan ' juga maka harus menunggu kenaikan () untuk menyelesaikan. Jalankan beberapa kali setiap varian.
sumber
Dalam sinkronisasi java, jika utas ingin masuk ke dalam metode sinkronisasi, ia akan mendapatkan kunci pada semua metode yang disinkronkan objek itu tidak hanya pada satu metode disinkronkan yang digunakan utas. Jadi thread yang mengeksekusi addA () akan mendapatkan kunci pada addA () dan addB () karena keduanya disinkronkan. Jadi utas lainnya dengan objek yang sama tidak dapat menjalankan addB ().
sumber
Ini mungkin tidak bekerja karena tinju dan autoboxing dari Integer ke int dan sebaliknya juga tergantung pada JVM dan ada kemungkinan besar bahwa dua nomor yang berbeda mungkin di-hash ke alamat yang sama jika mereka berada di antara -128 dan 127.
sumber