teks
Ketika pemrograman dalam lingkungan yang bersamaan, mekanisme kunci diperlukan untuk menyinkronkan operasi antara beberapa utas untuk memastikan akses yang saling eksklusif ke sumber daya bersama. Penguncian dapat menyebabkan kerusakan kinerja, yang tampaknya terkenal. Namun, penguncian itu sendiri tidak membawa banyak konsumsi kinerja, dan kinerja terutama merupakan proses memperoleh kunci di utas. Jika hanya ada satu utas yang bersaing untuk mengunci dan tidak ada kompetisi multi-thread saat ini, maka JVM akan mengoptimalkan, dan konsumsi kinerja yang disebabkan oleh penguncian pada dasarnya dapat diabaikan. Oleh karena itu, menstandarkan operasi penguncian, mengoptimalkan metode penggunaan penguncian, dan menghindari persaingan utas yang tidak perlu, tidak hanya dapat meningkatkan kinerja program, tetapi juga menghindari kemungkinan deadlocking utas yang disebabkan oleh penguncian yang tidak teratur dan meningkatkan ketahanan program. Berikut ini menjelaskan beberapa ide optimisasi kunci.
1. Cobalah untuk tidak mengunci metode ini
Ketika kunci ditambahkan ke fungsi anggota normal, utas memperoleh kunci objek objek tempat metode berada. Pada saat ini seluruh objek akan dikunci. Ini juga berarti bahwa jika beberapa metode sinkronisasi yang disediakan oleh objek ini untuk layanan yang berbeda, maka karena seluruh objek terkunci, ketika satu bisnis diproses, utas bisnis lain yang tidak terkait juga harus menunggu. Contoh berikut menunjukkan ini:
Kelas LockMethod berisi dua metode sinkronisasi, yang disebut dalam dua proses bisnis:
Kelas publik LockMethod {public disinkronkan void busia () {for (int i = 0; i <10000; i ++) {System.out.println (thread.currentThread (). getName ()+"berurusan dengan bisnis a:"+i); }} public disinkronkan void busib () {for (int i = 0; i <10000; i ++) {System.out.println (thread.currentThread (). getName ()+"berurusan dengan bisnis b:"+i); }}}BUSSA adalah kelas utas yang digunakan untuk menangani bisnis dan memanggil metode Busia () dari LockMethod:
BUSSB kelas publik memperluas thread {lockmethod lockmethod; void deal (lockmethod lockmethod) {this.lockmethod = lockMethod; } @Override public void run () {super.run (); lockmethod.busib (); }}TestLockMethod Class menggunakan Thread Bussa dan Bussb untuk pemrosesan bisnis:
TestLockMethod kelas publik memperluas thread {public static void main (string [] args) {lockMethod lockMethod = new LockMethod (); Bussa Bussa = Bussa baru (); BUSSB BUSSB = BUSSB baru (); Bussa.deal (LockMethod); Bussb.deal (LockMethod); bussa.start (); bussb.start (); }}Saat menjalankan program, Anda dapat melihat bahwa selama pelaksanaan Bussa Thread, Bussb tidak dapat memasukkan fungsi Bussib (), karena kunci objek LockMethod diperoleh oleh Bussa Thread.
2. Kurangi blok kode sinkron dan hanya kunci data
Terkadang untuk kenyamanan pemrograman, beberapa orang menyinkronkan sepotong kode besar. Jika beberapa operasi di blok kode ini tidak terkait dengan sumber daya bersama, mereka harus ditempatkan di luar blok sinkron untuk menghindari memegang kunci untuk waktu yang lama, menyebabkan utas lain tetap dalam keadaan menunggu. Terutama beberapa operasi siklus dan operasi I/O yang sinkron. Tidak hanya berarti mengurangi blok sinkronisasi dalam kisaran garis kode, tetapi juga dalam logika eksekusi, blok sinkronisasi harus dikurangi. Misalnya, tambahkan lebih banyak penilaian bersyarat dan sinkronisasi jika mereka memenuhi kondisi, daripada melakukan penilaian bersyarat setelah sinkronisasi, sehingga dapat meminimalkan logika yang tidak perlu memasuki blok sinkronisasi.
3. Cobalah untuk tidak memasukkan kunci di kunci
Situasi ini sering terjadi. Setelah utas mendapatkan A LOCK, ia memanggil metode sinkronisasi objek lain di blok metode sinkronisasi dan memperoleh kunci kedua. Ini dapat menyebabkan beberapa permintaan kunci dalam tumpukan panggilan. Dalam kasus multi-threading, ini dapat menyebabkan sangat kompleks dan sulit untuk menganalisis pengecualian, menghasilkan kebuntuan. Kode berikut menunjukkan ini:
disinkronkan (a) {disinkronkan (b) {}}Atau metode sinkronisasi dipanggil dalam blok sinkronisasi:
disinkronkan (a) {b b = objaRrayList.get (0); b.method (); // Ini adalah metode sinkronisasi}Solusinya adalah melompat keluar dan menambahkan kunci, dan tidak termasuk kunci:
{B b = null; disinkronkan (a) {b = objaRrayList.get (0); } b.method ();} 4. Privatisasi kunci dan kelola kunci secara internal
Lebih aman menggunakan kunci sebagai objek pribadi, dan tidak dapat diperoleh dari luar. Objek dapat dikunci langsung oleh utas lain, dan utas memegang kunci objek objek, misalnya:
class a {public void method1 () {}} class b {public void method1 () {a a = new a (); disinkronkan (a) {// langsung kunci a.method1 (); }}}Dalam cara penggunaan ini, kunci objek objek A dipegang oleh luar, sehingga lebih berbahaya untuk membiarkan kunci digunakan di beberapa tempat di luar, dan juga menyebabkan masalah membaca aliran logis kode. Cara yang lebih baik adalah mengelola kunci sendiri di dalam kelas dan menyediakan operasi sinkronisasi melalui antarmuka ketika skema sinkron eksternal diperlukan: diperlukan:
kelas A {private objek lock = objek baru (); public void method1 () {disinkronkan (lock) {}}} class b {public void method1 () {a = new a (); a.method1 (); }} 5. Lakukan dekomposisi kunci yang sesuai
Pertimbangkan prosedur berikut:
Public Class Gameserver {peta publik <String, List <layer>> TABLE = new HashMap <String, List <layer> (); public void goint (pemain pemain, tabel tabel) {if (player.getAccountBaLance ()> table.getLyMit ()) {disinkronkan (tabel) {daftar <layer> tablePlayers = TABLE.get (TABLE.GetID ()); if (tabelplayers.size () <9) {tablePlayers.add (player); }}}}} public void cuti (pemain player, tabel tabel) {/*oMit*/} public void createTable () {/*oMit*/} public void DestroyTable (tabel tabel) {/*oMit*/}}Dalam contoh ini, metode gabungan hanya menggunakan satu kunci sinkronisasi untuk mendapatkan objek daftar <layer> dalam tabel, dan kemudian menentukan apakah jumlah pemain kurang dari 9. Jika demikian, tambahkan satu pemain. Ketika ada ribuan daftar <layer> di tabel, kompetisi untuk tabel kunci akan sangat sengit. Di sini, kita dapat mempertimbangkan untuk menguraikan kunci: setelah dengan cepat mengambil data, mengunci objek daftar <layer>, sehingga utas lain dapat dengan cepat bersaing untuk mendapatkan kunci objek Tabel:
GameServer kelas publik {
peta publik <string,
Daftar <layer>> Tabel = hashmap baru <string,
Daftar <layer>> ();
public void gabungan (pemain pemain, meja meja) {
if (player.getAccountBalance ()> TABLE.GETIMIT ()) {
Daftar <layer> TablePlayers = null;
disinkronkan (tabel) {
TablePlayers = Table.get (Table.GetId ());
}
Sinkronisasi (TablePlayers) {
if (tabelplayers.size () <9) {
TablePlayers.Add (pemain);
}
}
}
}
cuti public void (pemain pemain, meja meja) {
/*Dihilangkan*/
}
public void createTable () {
/*Dihilangkan*/
}
public void hancur (tabel tabel) {
/*Dihilangkan*/
}
}