Apakah kunci kelas dan kunci objek akan bertentangan? Apakah kunci objek dan kunci pribadi akan bertentangan? Ilustrasi melalui contoh.
1. Perjanjian Terkait
Untuk memperjelas uraian berikut, pertama-tama kami membuat konvensi berikut tentang definisi kunci yang relevan yang terlibat dalam artikel ini:
1. Kunci kelas: Tambahkan kunci statis dan tersinkronisasi ke metode dalam kode, atau segmen kode tersinkronisasi (xxx.class), seperti increament() di bawah;
2. Kunci objek: Tambahkan kunci tersinkronisasi ke metode dalam kode, atau segmen kode (ini) yang tersinkronisasi, seperti synOnMethod() dan synInMethod() di bawah;
3. Kunci pribadi: Deklarasikan properti pribadi seperti kunci Objek pribadi di dalam kelas, dan sinkronkan (kunci) segmen kode yang perlu dikunci, seperti synMethodWithObj() di bawah.
2. Kode uji
1. Tulis kelas startup ObjectLock
Copy kode kodenya sebagai berikut:
kelas publik ObjectLock {
public static void main(String[] args) {
System.out.println("waktu mulai = " + System.currentTimeMillis()+"ms");
Tes LockTestClass = LockTestClass baru();
untuk (int saya = 0; saya < 3; saya++) {
Utas utas = ObjThread baru(tes, i);
thread.mulai();
}
}
}
2. Tulis kelas thread ObjThread untuk memulai metode sinkronisasi (perhatikan bahwa metode eksekusinya dapat disesuaikan untuk pengujian yang berbeda)
Copy kode kodenya sebagai berikut:
kelas publik ObjThread memperluas Thread {
Kunci LockTestClass;
ke dalam saya = 0;
ObjThread publik(Kunci LockTestClass, int i) {
this.lock = kunci;
ini.i = saya;
}
menjalankan kekosongan publik() {
//Metode tanpa kunci
//lock.noSynMethod(ini.getId(),ini);
//Metode kunci objek 1, menggunakan synInMethod yang disinkronkan
lock.synInMethod();
//Metode kunci objek 2, menggunakan metode tersinkronisasi(ini).
//lock.synOnMethod();
//Metode kunci pribadi, menggunakan metode tersinkronisasi (objek).
//lock.synMethodWithObj();
//Metode kunci kelas, menggunakan metode kenaikan tersinkronisasi statis
LockTestClass.peningkatan();
}
}
3. Tulis kelas uji kunci lainnya LockTestClass, termasuk berbagai metode penguncian
Copy kode kodenya sebagai berikut:
kelas publik LockTestClass {
//Digunakan untuk penghitungan kunci kelas
int statis pribadi i = 0;
//Kunci pribadi
objek Objek pribadi = Objek baru();
/**
* <p>
* Metode bebas kunci
*
* @param threadID
* @param utas
*/
public void noSynMethod(ID thread panjang, thread ObjThread) {
System.out.println("nosyn: objek kelas adalah " + thread + ", threadId adalah"
+ ID utas);
}
/**
* Metode kunci objek 1
*/
void synOnMethod() yang disinkronkan secara publik() {
System.out.println("synOnMethod dimulai" + ", waktu = "
+ Sistem.currentTimeMillis() + "ms");
mencoba {
Thread.tidur (2000L);
} tangkapan (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synOnMethod berakhir");
}
/**
* Metode kunci objek 2, gunakan sinkronisasi (ini) untuk mengunci
*/
kekosongan publik synInMethod() {
disinkronkan (ini) {
System.out.println("synInMethod dimulai" + ", waktu = "
+ Sistem.currentTimeMillis() + "ms");
mencoba {
Thread.tidur (2000L);
} tangkapan (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synInMethod berakhir");
}
}
/**
* Metode kunci objek 3
*/
kekosongan publik synMethodWithObj() {
disinkronkan (objek) {
System.out.println("synMethodWithObj dimulai" + ", waktu = "
+ Sistem.currentTimeMillis() + "ms");
mencoba {
Thread.tidur (2000L);
} tangkapan (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synMethodWithObj berakhir");
}
}
/**
* Kunci kelas
*/
peningkatan kekosongan tersinkronisasi statis publik() {
System.out.println("kelas disinkronkan.i = " + i + ", waktu = "
+ Sistem.currentTimeMillis() + "ms");
saya++;
mencoba {
Thread.tidur (2000L);
} tangkapan (InterruptedException e) {
e.printStackTrace();
}
System.out.println("kelas tersinkronisasi berakhir.");
}
}
3. Hasil tes
1. Untuk menguji kunci kelas dan kunci objek, modifikasi metode run ObjectThread sebagai berikut:
Copy kode kodenya sebagai berikut:
menjalankan kekosongan publik() {
//Metode tanpa kunci
//lock.noSynMethod(ini.getId(),ini);
//Metode kunci objek 1, menggunakan synInMethod yang disinkronkan
lock.synInMethod();
//Metode kunci objek 2, menggunakan metode tersinkronisasi(ini).
//lock.synOnMethod();
//Metode kunci pribadi, menggunakan metode tersinkronisasi (objek).
//lock.synMethodWithObj();
//Metode kunci kelas, menggunakan metode kenaikan tersinkronisasi statis
LockTestClass.increament();
}
Keluaran terminal:
Copy kode kodenya sebagai berikut:
waktu mulai = 1413101360231ms
synInMethod dimulai, waktu = 1413101360233ms
synInMethod berakhir
kelas disinkronkan. i = 0, waktu = 1413101362233ms
synInMethod dimulai, waktu = 1413101362233ms
kelas disinkronkan berakhir.
synInMethod berakhir
kelas disinkronkan. i = 1, waktu = 1413101364233ms
synInMethod dimulai, waktu = 1413101364233ms
kelas disinkronkan berakhir.
synInMethod berakhir
kelas disinkronkan. i = 2, waktu = 1413101366234ms
kelas disinkronkan berakhir.
Anda dapat melihat bahwa metode kunci objek (synInMothod) 2 detik lebih cepat daripada metode kunci kelas (increament) saat pertama kali dimulai. Hal ini karena ketika synInMehtod dijalankan, ia tidur selama 2 detik dan kemudian mengeksekusi increament, dan keduanya. metode berbagi thread yang sama Jadi akan lebih lambat 2 detik. Jika increament ditempatkan di depan synInMethod saat dijalankan, maka increament akan menjadi 2 detik lebih cepat saat dimulai untuk pertama kalinya.
Ketika metode kunci kelas dimulai, metode kunci objek dari thread lain juga dimulai hampir pada waktu yang sama, menunjukkan bahwa keduanya tidak menggunakan kunci yang sama dan tidak akan ada persaingan.
Kesimpulan: Kunci kelas dan kunci objek tidak akan bersaing, dan metode pengunciannya tidak akan saling mempengaruhi.
2. Kunci pribadi dan kunci objek, metode eksekusi ObjectThread dimodifikasi sebagai berikut:
Copy kode kodenya sebagai berikut:
menjalankan kekosongan publik() {
//Metode tanpa kunci
//lock.noSynMethod(ini.getId(),ini);
//Metode kunci objek 1, menggunakan synInMethod yang disinkronkan
lock.synInMethod();
//Metode kunci objek 2, menggunakan metode tersinkronisasi(ini).
//lock.synOnMethod();
//Metode kunci pribadi, menggunakan metode tersinkronisasi (objek).
lock.synMethodWithObj();
//Metode kunci kelas, menggunakan metode kenaikan tersinkronisasi statis
//LockTestClass.increament();
}
Keluaran terminal:
Copy kode kodenya sebagai berikut:
waktu mulai = 1413121912406ms
synInMethod dimulai, waktu = 1413121912407ms.
synInMethod berakhir.
synMethodWithObj dimulai, waktu = 1413121914407ms
synInMethod dimulai, waktu = 1413121914407ms.
synInMethod berakhir.
synMethodWithObj berakhir
synInMethod dimulai, waktu = 1413121916407ms.
synMethodWithObj dimulai, waktu = 1413121916407ms
synInMethod berakhir.
synMethodWithObj berakhir
synMethodWithObj dimulai, waktu = 1413121918407ms
synMethodWithObj berakhir
Sangat mirip dengan kunci kelas dan kunci objek.
Kesimpulan: Kunci pribadi dan kunci objek tidak akan bersaing, dan metode pengunciannya tidak akan saling mempengaruhi.
3.Synchronized langsung ditambahkan ke metode dan disinkronkan (ini), dan metode run ObjectThread dimodifikasi sebagai berikut:
Copy kode kodenya sebagai berikut:
menjalankan kekosongan publik() {
//Metode tanpa kunci
//lock.noSynMethod(ini.getId(),ini);
//Metode kunci objek 1, menggunakan synInMethod yang disinkronkan
lock.synInMethod();
//Metode kunci objek 2, menggunakan metode tersinkronisasi(ini).
lock.synOnMethod();
//Metode kunci pribadi, menggunakan metode tersinkronisasi (objek).
//lock.synMethodWithObj();
//Metode kunci kelas, menggunakan metode kenaikan tersinkronisasi statis
//LockTestClass.increament();
}
Keluaran terminal:
Copy kode kodenya sebagai berikut:
waktu mulai = 1413102913278ms
synInMethod dimulai, waktu = 1413102913279ms
synInMethod berakhir
synInMethod dimulai, waktu = 1413102915279ms
synInMethod berakhir
synOnMethod dimulai, waktu = 1413102917279ms
synOnMethod berakhir
synInMethod dimulai, waktu = 1413102919279ms
synInMethod berakhir
synOnMethod dimulai, waktu = 1413102921279ms
synOnMethod berakhir
synOnMethod dimulai, waktu = 1413102923279ms
synOnMethod berakhir
Seperti yang Anda lihat, kedua keluaran tersebut benar-benar serial (tentu saja, apakah synInMethod atau synOnMethod dijalankan terlebih dahulu saat dijalankan kembali tidak ditentukan, bergantung pada siapa yang mendapatkan kuncinya).
Kesimpulan: sinkronisasi langsung ditambahkan ke metode dan sinkronisasi (ini) keduanya mengunci objek saat ini. Kedua metode penguncian berada dalam hubungan yang kompetitif, dan hanya satu metode yang dapat dijalankan pada waktu yang sama.