Metode statis tersinkronisasi Java: mengunci objek atau kelas

148

Dokumentasi Java mengatakan:

Tidak mungkin untuk dua pemanggilan metode yang disinkronkan pada objek yang sama untuk interleave.

Apa artinya ini untuk metode statis? Karena metode statis tidak memiliki objek terkait, akankah kata kunci yang disinkronkan mengunci di kelas, bukan objek?

jbu
sumber

Jawaban:

129

Karena metode statis tidak memiliki objek terkait, akankah kata kunci yang disinkronkan mengunci di kelas, bukan objek?

Iya. :)

OscarRyz
sumber
81
Tolong jawab Elaborate sehingga semua orang bisa mengerti.
Madhu
6
@ Madhu. Ini berarti bahwa jika Anda memiliki 2 atau lebih metode yang disinkronkan pada kelas yang sama, keduanya tidak dapat dieksekusi pada waktu yang sama, bahkan ketika ada beberapa contoh kelas itu. Penguncian pada dasarnya sama dengan mengunci pada Object.class untuk setiap metode yang disinkronkan.
Steven
Jawaban ini salah - thisapakah kunci diperoleh pada metode instan-, mohon perbaiki Oscar.
vemv
1
@ vemv Pertanyaannya adalah tentang metode kelas, bukan metode contoh.
OscarRyz
23
@vemv Ya, untuk memahami jawaban Anda harus membaca pertanyaan terlebih dahulu.
OscarRyz
199

Hanya untuk menambahkan sedikit detail pada jawaban Oscar (menyenangkan ringkas!), Bagian yang relevan pada Spesifikasi Bahasa Jawa adalah 8.4.3.6, 'Metode yang disinkronkan' :

Metode yang disinkronkan memperoleh monitor ( §17.1 ) sebelum dijalankan. Untuk metode kelas (statis), monitor yang terkait dengan objek Kelas untuk kelas metode digunakan. Untuk metode instan, monitor yang terkait dengan ini (objek yang digunakan metode ini) digunakan.

Cowan
sumber
17
Berguna, saya sedang mencari kutipan +1
OscarRyz
80

Satu hal yang Anda harus berhati-hati (beberapa programmer umumnya jatuh dalam perangkap itu) adalah bahwa tidak ada hubungan antara metode statis yang disinkronkan dan metode non-statis yang disinkronkan, yaitu:

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

Utama:

A a = new A();

Utas 1:

A.f();

Utas 2:

a.g();

f () dan g () tidak disinkronkan satu sama lain dan dengan demikian dapat mengeksekusi secara bersamaan.

jfpoilpret
sumber
18
tetapi bagaimana jika g () memutasikan beberapa variabel statis yang dibaca f (). Bagaimana cara membuat utas itu aman? Apakah kita secara eksplisit mendapatkan kunci di kelas?
baskin
22
Ya, metode non-statis Anda harus menyinkronkan secara eksplisit pada kelas itu sendiri (yaitu synchronized (MyClass.class) {...},.
jfpoilpret
@jfpoilpret "disinkronkan (MyClass.class) {...}" setara dengan membuat metode ini disinkronkan secara statis, bukan?
crazymind
15

Kecuali Anda menerapkan g () sebagai berikut:

g() {
    synchronized(getClass()) {
        ...
    }
}

Saya menemukan pola ini berguna juga ketika saya ingin menerapkan saling pengecualian antara berbagai contoh objek (yang diperlukan ketika mengakses sumber daya eksternal, misalnya).

coba-tangkap-akhirnya
sumber
63
Perhatikan bahwa sebenarnya ada kemungkinan beberapa bug yang sangat halus dan tidak menyenangkan di sini. Ingatlah untuk getClass()mengembalikan tipe runtime ; jika Anda mensubclass kelas, maka kelas induk dan kelas anak akan disinkronkan pada kunci yang berbeda. synchronized(MyClass.class)adalah cara untuk pergi jika Anda perlu memastikan semua contoh menggunakan kunci yang sama.
Cowan
4

Lihat halaman dokumentasi oracle tentang Kunci dan Sinkronisasi Intrinsik

Anda mungkin bertanya-tanya apa yang terjadi ketika metode sinkronisasi statis dipanggil, karena metode statis dikaitkan dengan kelas, bukan objek. Dalam kasus ini, utas memperoleh kunci intrinsik untuk objek Kelas yang terkait dengan kelas . Dengan demikian akses ke bidang statis kelas dikendalikan oleh kunci yang berbeda dari kunci untuk instance kelas apa pun .

Ravindra babu
sumber
2

Metode statis juga memiliki objek terkait. Itu milik file Class.class di JDK toolkit. Ketika file .class dimuat ke dalam ram, Class.class membuat sebuah instance yang disebut objek template.

Misalnya: - ketika Anda mencoba membuat objek dari kelas pelanggan yang sudah ada seperti

Customer c = new Customer();

Kelas Pelanggan memuat ke dalam RAM. Pada saat itu, Class.class di JDK toolkit membuat Objek yang disebut objek Templat dan memuat yang Customer.class ke objek templat itu. Anggota statis dari Customer.class itu menjadi atribut dan metode dalam objek templat itu.

Jadi metode atau atribut statis juga memiliki objek

Pahansith Gunathilake
sumber
2

Contoh di bawah ini memberikan lebih banyak kejelasan antara kelas dan objek kunci, berharap contoh di bawah ini akan membantu orang lain juga :)

Sebagai contoh kita memiliki metode di bawah ini satu memperoleh kelas dan lainnya memperoleh kunci objek:

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

Jadi, sekarang kita dapat memiliki skenario berikut:

  1. Ketika utas menggunakan Objek yang sama mencoba mengakses metode objLock ATAU staticLock waktu yang sama (yaitu kedua utas mencoba mengakses metode yang sama)

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
    
  2. Ketika utas menggunakan Objek yang sama mencoba mengakses staticLockdan objLockmetode waktu yang sama (mencoba mengakses metode yang berbeda)

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
    
  3. Ketika utas menggunakan Objek berbeda mencoba mengakses staticLockmetode

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
    
  4. Ketika utas menggunakan Objek berbeda mencoba mengakses objLockmetode

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
    
Ravi
sumber
0

Bagi mereka yang tidak terbiasa metode sinkronisasi statis terkunci pada objek kelas misalnya untuk kelas string-nya String.class sementara metode disinkronkan mengunci pada instance saat ini dari Obyek yang dilambangkan dengan kata kunci "this" di Jawa. Karena kedua objek ini berbeda, mereka memiliki kunci yang berbeda sehingga ketika satu utas menjalankan metode tersinkronisasi statis, utas lainnya di java tidak perlu menunggu utas itu kembali, melainkan akan memperoleh kunci terpisah yang ditandai byte .class literal dan masuk ke metode tersinkronisasi statis.

Pragya
sumber