Di Java 8, saya dapat dengan mudah menulis:
interface Interface1 {
default void method1() {
synchronized (this) {
// Something
}
}
static void method2() {
synchronized (Interface1.class) {
// Something
}
}
}
Saya akan mendapatkan semantik sinkronisasi penuh yang dapat saya gunakan juga di kelas. Namun saya tidak bisa menggunakan synchronized
pengubah pada deklarasi metode:
interface Interface2 {
default synchronized void method1() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
static synchronized void method2() {
// ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
}
}
Sekarang, orang dapat berargumen bahwa kedua antarmuka berperilaku dengan cara yang sama kecuali yang Interface2
membuat kontrak terus method1()
-menerus method2()
, yang sedikit lebih kuat daripada apa yang Interface1
dilakukan. Tentu saja, kami mungkin juga berpendapat bahwa default
implementasi tidak boleh membuat asumsi tentang keadaan implementasi konkret, atau bahwa kata kunci seperti itu tidak akan menarik.
Pertanyaan:
Apa alasan mengapa kelompok ahli JSR-335 memutuskan untuk tidak mendukung synchronized
metode antarmuka?
java
java-8
synchronized
default-method
jsr335
Lukas Eder
sumber
sumber
default synchronized
, tetapi belum tentu untukstatic synchronized
, meskipun saya akan menerima bahwa yang terakhir mungkin telah dihilangkan karena alasan konsistensi.synchronized
pengubahnya mungkin ditimpa dalam subkelas, maka itu hanya masalah jika ada sesuatu sebagai metode default akhir. (Pertanyaan Anda yang lain)synchronized
di kelas super, secara efektif menghapus sinkronisasi. Saya tidak akan terkejut bahwa tidak mendukungsynchronized
dan tidak mendukungfinal
terkait, mungkin karena beberapa pewarisan (misalnya mewarisivoid x()
dansynchronized void x()
, dll.). Tapi itu spekulasi. Saya ingin tahu tentang alasan otoritatif, jika ada.super
yang membutuhkan implementasi ulang penuh dan kemungkinan akses ke anggota pribadi. Btw, ada alasan metode-metode itu disebut "pembela" - mereka hadir untuk memudahkan menambahkan metode baru.Jawaban:
Meskipun pada awalnya mungkin tampak jelas bahwa seseorang ingin mendukung
synchronized
pengubah pada metode default, ternyata hal itu akan berbahaya, dan itu dilarang.Metode yang disinkronkan adalah singkatan untuk metode yang berperilaku seolah-olah seluruh tubuh tertutup dalam
synchronized
blok yang objek kuncinya adalah penerima. Tampaknya masuk akal untuk memperluas semantik ini ke metode standar juga; setelah semua, mereka adalah metode instan dengan penerima juga. (Perhatikan bahwasynchronized
metode sepenuhnya merupakan optimasi sintaksis; mereka tidak diperlukan, mereka hanya lebih kompak daripadasynchronized
blok yang sesuai . Ada argumen yang masuk akal untuk dibuat bahwa ini adalah optimasi sintaksis prematur di tempat pertama, dan metode yang disinkronkan menyebabkan lebih banyak masalah daripada yang mereka pecahkan, tetapi kapal itu berlayar sejak lama.)Jadi, mengapa mereka berbahaya? Sinkronisasi adalah tentang penguncian. Mengunci adalah tentang mengoordinasikan akses bersama untuk keadaan yang bisa berubah. Setiap objek harus memiliki kebijakan sinkronisasi yang menentukan kunci mana yang melindungi variabel keadaan. (Lihat Java Concurrency in Practice , bagian 2.4.)
Banyak objek yang digunakan sebagai kebijakan sinkronisasi Java Monitor Pattern (JCiP 4.1), di mana keadaan objek dijaga oleh kunci intrinsiknya. Tidak ada yang ajaib atau istimewa tentang pola ini, tetapi itu nyaman, dan penggunaan
synchronized
kata kunci pada metode secara implisit mengasumsikan pola ini.Kelaslah yang memiliki status yang dapat menentukan kebijakan sinkronisasi objek itu. Tetapi antarmuka tidak memiliki keadaan objek yang dicampur. Jadi, menggunakan metode yang disinkronkan dalam antarmuka mengasumsikan kebijakan sinkronisasi tertentu, tetapi yang Anda tidak memiliki dasar yang masuk akal untuk mengasumsikan, sehingga mungkin terjadi bahwa penggunaan sinkronisasi tidak memberikan keselamatan benang tambahan apa pun (Anda mungkin menyinkronkan kunci yang salah). Ini akan memberi Anda kepercayaan diri yang salah bahwa Anda telah melakukan sesuatu tentang keamanan utas, dan tidak ada pesan kesalahan yang memberi tahu Anda bahwa Anda menganggap kebijakan sinkronisasi salah.
Sudah cukup sulit untuk secara konsisten mempertahankan kebijakan sinkronisasi untuk satu file sumber; bahkan lebih sulit untuk memastikan bahwa subkelas dengan benar mematuhi kebijakan sinkronisasi yang ditentukan oleh superclass-nya. Mencoba melakukannya antara kelas-kelas yang digabungkan secara longgar (sebuah antarmuka dan kemungkinan banyak kelas yang mengimplementasikannya) akan hampir mustahil dan sangat rawan kesalahan.
Mengingat semua argumen itu bertentangan, untuk apa argumen itu? Sepertinya mereka kebanyakan tentang membuat antarmuka berperilaku lebih seperti ciri-ciri. Meskipun ini adalah keinginan yang dapat dimengerti, pusat desain untuk metode standar adalah evolusi antarmuka, bukan "Ciri -". Di mana keduanya dapat dicapai secara konsisten, kami berusaha untuk melakukannya, tetapi di mana satu bertentangan dengan yang lain, kami harus memilih yang mendukung tujuan desain utama.
sumber
synchronized
pengubah metode muncul di keluaran javadoc, menyesatkan orang untuk berpikir bahwa itu adalah bagian dari spesifikasi. Ini diperbaiki di JDK 1.2. Bahkan jika itu muncul pada metode publik,synchronized
pengubah adalah bagian dari implementasi, bukan kontrak. (Penalaran dan perawatan yang serupa juga terjadi padanative
modifikator.)synchronized
dan mengaitkan komponen yang aman di sekitar dan Anda memiliki program yang hampir aman. Masalahnya adalah ini biasanya bekerja dengan baik tetapi rusak dengan cara yang mengejutkan dan rapuh. Saya setuju bahwa memahami cara kerja penguncian Anda adalah kunci untuk aplikasi yang kuat.synchronized(this) {...}
diijinkan dalam suatudefault
metode? (Seperti yang ditunjukkan dalam pertanyaan Lukas.) Bukankah itu memungkinkan metode default untuk memiliki status kelas implementasi juga? Bukankah kita juga ingin mencegahnya? Apakah kita memerlukan aturan FindBugs untuk menemukan kasus-kasus yang dilakukan pengembang yang tidak mendapat informasi?synchronized(vector)
. Jika Anda ingin aman, Anda tidak boleh menggunakan objek publik (sepertithis
itu sendiri) untuk mengunci.hasil:
(maaf karena menggunakan kelas induk sebagai contoh)
dari hasilnya, kita bisa tahu bahwa kunci kelas induk dimiliki oleh setiap sub kelas, objek SonSync1 dan SonSync2 memiliki kunci objek yang berbeda. setiap kunci adalah independensi. jadi dalam hal ini, saya pikir itu tidak berbahaya menggunakan disinkronkan di kelas induk atau antarmuka umum. adakah yang bisa menjelaskan lebih lanjut tentang ini?
sumber