Artikel ini terutama mempelajari kode sampel aplikasi kondisi pemblokiran kondisi konkurensi Java, sebagai berikut.
Kondisi memecah metode monitor objek (tunggu, beri tahu, dan beri tahu semua) menjadi objek yang sama sekali berbeda sehingga dengan menggabungkan objek-objek ini dengan implementasi kunci apa pun, setiap objek menyediakan beberapa set menunggu (tunggu-set). Di antara mereka, kunci menggantikan penggunaan metode dan pernyataan yang disinkronkan, dan kondisi menggantikan penggunaan metode monitor objek.
Karena kondisi dapat digunakan untuk mengganti Wait, Notify dan Metode Lainnya, kita dapat membandingkan kode komunikasi antar-utara yang ditulis sebelumnya dan melihat masalah aslinya:
Ada dua utas. Utas anak dieksekusi 10 kali lebih dulu, kemudian utas utama dieksekusi 5 kali, kemudian beralih ke utas anak mengeksekusi 10, dan kemudian utas utama mengeksekusi 5 kali ... perjalanan pulang pergi ini 50 kali.
Saya menggunakan menunggu dan memberi tahu untuk mengimplementasikannya sebelumnya, tetapi sekarang saya menggunakan kondisi untuk menulis ulang, kodenya adalah sebagai berikut:
Public Class ConditionCommunication {public static void main (string [] args) {bisnis bisnis = bisnis baru (); utas baru (runnable baru () {// buka thread anak @Override public void run () {for (int i = 1; i <= 50; i ++) {BusSiness.sub (i)}}}}} {iN (i) {i+} {iN (i) {iN; 50; {condition.aWait (); // Gunakan kondisi untuk memanggil metode AWAIT} catch (Exception e) {// TODO TODO AUTO-AUTO-ENTERATED BLOCKE.PRINTSTACKTRACE ();}} untuk (int j = 1; j <= 10; j ++) {System.println ("Sub Thread Sequence of" + J + J ++) {Systems.println ("sub thread dari" + j ++) false; condition.signal (); // Gunakan kondisi untuk mengirim sinyal bangun dan bangunkan yang tertentu} akhirnya {lock.unlock ();}} public void main (int i) {lock.lock (); coba {whiledouldsub) {coba {condition.Await (); blocke.printstacktrace ();}} untuk (int j = 1; j <= 10; j ++) {System.out.println ("Urutan utas utama" + j + ", loop dari" + i);}}}}}} {}} {}} {} {} {} {} {} {} {} {} {} {{} tertentu)Dari sudut pandang kode, kondisi digunakan bersama dengan kunci. Tanpa kunci, kondisi tidak dapat digunakan, karena kondisi dibuat melalui kunci. Penggunaan ini sangat sederhana. Selama Anda menguasai penggunaan yang disinkronkan, tunggu, dan beri tahu, Anda dapat sepenuhnya menguasai penggunaan kunci dan kondisi.
Di atas menggunakan kunci dan kondisi alih -alih metode monitor yang disinkronkan dan objek untuk mewujudkan komunikasi antara dua utas. Sekarang mari kita tulis aplikasi yang sedikit lebih canggih: simulasikan antrian pemblokiran buffer.
Apa itu buffer? Misalnya, ada banyak orang yang ingin mengirim pesan sekarang. Saya adalah stasiun transit dan saya ingin membantu orang lain mengirim pesan. Jadi sekarang saya perlu melakukan dua hal. Satu hal adalah menerima pesan yang dikirim oleh pengguna dan memasukkannya ke dalam buffer secara berurutan. Hal lain adalah mengambil pesan yang dikirim oleh pengguna secara berurutan dari buffer dan mengirimkannya.
Sekarang abstrak masalah aktual ini: buffer adalah array. Kami dapat menulis data ke dalam array atau mengeluarkan data dari array. Dua hal yang perlu saya lakukan adalah memulai dua utas, satu untuk menyimpan data dan yang lain untuk mendapatkan data. Tetapi masalahnya adalah bahwa jika buffer penuh, itu berarti ada terlalu banyak pesan yang diterima, yaitu pesan yang dikirim terlalu cepat, dan utas lain dalam hidup saya tidak cukup untuk mengirimkannya, mengakibatkan buffer ditinggalkan, sehingga utas penyimpanan data harus diblokir dan biarkan menunggu; Sebaliknya, jika saya meneruskannya terlalu cepat, dan sekarang semua isi buffer telah dikirim oleh saya dan tidak ada pesan baru yang dikirim oleh pengguna, maka utas akuisisi data harus diblokir saat ini.
OK, setelah menganalisis antrian pemblokiran buffer ini, mari kita gunakan teknologi kondisi untuk mengimplementasikannya:
BUFFER CLASS {Final Lock Lock = baru reentrantlock (); // Tentukan Kunci Kunci Final Notfull = Lock.NewCondition (); // Tentukan kondisi ConditionFinal Notempty = lock.newcondition (); // Tentukan Objek ConditionFinal [] Items = New Object [10]; // Untuk simulasi berikut, menetapkan ukuran blokinfinal []. Count; // Array Subscript digunakan untuk mengkalibrasi posisi // data penyimpanan ke dalam antrian public void put (objek x) melempar interruptedException {lock.lock (); // lock cobalah {while (count == item.length) {System.out.println (thread.currentThread (). getName) {System.out.println (thread.currentThread (). getName () + "DATEDN, BEEKT.CURRENTEDRAD (). GetName () +" DATA, COUREDE BEEKR.CURRENTTRAD (). Menjadi! "); Takti -khas. Jika tercapai, kembalilah ke putptr awal = 0; ++ count; // Jumlah Sistem Pesan.out.println (thread.currentThread (). GetName () + "Simpan nilainya:" + x); notempty.signal (); // oke, sekarang ada data dalam antrian. Bangunkan utas dengan antrian kosong dan Anda bisa mendapatkan data} akhirnya {lock.unlock (); // Unduh kunci}} // Ambil data dari objek publik antrian () melempar interruptedException {lock.lock (); // lock coba {wheT (count == 0) {System.out.printlok (); Diperoleh untuk saat ini! "); notempty.aWait (); // Jika antriannya kosong, maka utas itu memblokir data untuk mengambil utas, menunggu untuk dibangunkan} // jika tidak kosong, ambil objek x = item-TakePtr]; jika terjadi, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu mencakup, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, jika itu, Take (++ TakePtr == item. Jumlah pesan System.out.println (thread.currentThread (). getName () + "Keluarlah nilainya:" + x); tispull.signal (); // oke, sekarang ada lokasi dalam antrian. Bangunkan utas yang penuh dengan antrian dan Anda dapat menyimpan data. Return x;} akhirnya {lock.unlock (); // lock}}}Program ini klasik, saya mengeluarkannya dari dokumentasi JDK resmi dan menambahkan komentar. Ada dua kondisi yang ditentukan dalam program ini, yang digunakan untuk menjalankan dua utas, dan menunggu dan bangun masing -masing. Idenya jelas dan programnya juga sangat kuat. Satu pertanyaan dapat dipertimbangkan, mengapa Anda perlu menggunakan dua kode? Pasti ada alasan untuk desain ini. Jika Anda menggunakan suatu kondisi, sekarang asumsikan bahwa antriannya penuh, tetapi ada 2 utas A dan B yang menyimpan data secara bersamaan, maka mereka semua memasuki tidur. Oke, sekarang utas lain mengambil satu dan kemudian bangun salah satu utas A, lalu A Can Save It. Setelah menabung, bangun utas lain. Jika B dibangunkan, akan ada masalah, karena antriannya penuh saat ini dan B tidak dapat menyimpannya. Jika B menyimpan, itu akan menimpa nilai yang belum diambil. Karena suatu kondisi digunakan, penyimpanan dan penarikan menggunakan kondisi ini untuk tidur dan bangun, dan itu akan kacau. Pada titik ini, Anda dapat memahami penggunaan kondisi ini. Sekarang mari kita uji efek antrian pemblokiran di atas:
public class BoundedBuffer {public static void main(String[] args) {Buffer buffer = new Buffer();for (int i = 0; i < 5; i ++) {//Open 5 threads to store data in the buffer new Thread(new Runnable() {@Override public void run() {try {buffer.put(new Random().nextint(1000));//Save data randomly}catch (InterruptedException e) {e.printStackTrace();}}}).start();}for (int i = 0; i < 10; i ++) {//Open 10 threads to get data from the buffer new Thread(new Runnable() {@Override public void run() {try {buffer.take();//Fetch data from the buffer}catch (InterruptedException e) {e.printstacktrace ();}}}). start ();}}}}Saya sengaja mengaktifkan 5 utas untuk menyimpan data dan 10 utas untuk mengambil data, hanya untuk membuatnya diblokir dari mendapatkan data, dan melihat hasil operasi:
Thread-5 diblokir dan data tidak dapat diambil untuk saat ini!
Thread-10 diblokir dan data tidak dapat diambil untuk saat ini!
Nilai Thread-1 yang disimpan: 755
Nilai Simpan Thread-0: 206
Nilai Thread-2 Disimpan: 741
Thread-3 Nilai Disimpan: 381
Nilai Thread-14 Dihapus: 755
Thread-4 Nilai Disimpan: 783
Thread-6 Keluarkan Nilai: 206
Thread-7 Nilai Dihapus: 741
Thread-8 Nilai Dihapus: 381
Thread-9 Mengambil Nilai: 783
Thread-5 diblokir dan data tidak dapat diambil untuk saat ini!
Thread-11 diblokir dan data tidak dapat diambil untuk saat ini!
Thread-12 diblokir dan data tidak dapat diambil untuk saat ini!
Thread-10 diblokir dan data tidak dapat diambil untuk saat ini!
Thread-13 diblokir dan data tidak dapat diambil untuk saat ini!
Dari hasilnya, kita dapat melihat bahwa utas 5 dan 10 dieksekusi terlebih dahulu, dan mereka menemukan bahwa tidak ada dalam antrian, sehingga mereka diblokir dan tidur di sana. Mereka hanya bisa mendapatkannya sampai nilai baru disimpan dalam antrian. Namun, mereka tidak beruntung, dan data yang disimpan diambil terlebih dahulu oleh utas lain. Haha ... mereka dapat menjalankannya beberapa kali lagi. Jika Anda ingin melihat data yang disimpan diblokir, Anda dapat mengatur utas untuk mengambil data sedikit lebih sedikit, dan saya tidak akan mengaturnya di sini.
Ini masih pertanyaan yang sama seperti sebelumnya. Sekarang biarkan tiga utas menjalankannya. Mari kita lihat pertanyaannya:
Ada tiga utas, benang anak 1 dieksekusi 10 kali pertama, benang anak 2 dieksekusi 10 kali, kemudian utas utama dieksekusi 5 kali, kemudian beralih ke benang anak 1 dieksekusi 10 kali, benang anak 2 mengeksekusi 10 kali, utas utama dieksekusi 5 kali ... Perjalanan pulang pergi ini 50 kali.
Jika Anda tidak menggunakan kondisi, itu sangat sulit dilakukan, tetapi sangat nyaman untuk melakukannya dengan kondisi. Prinsipnya sangat sederhana. Tentukan tiga kondisi. Setelah Thread Anak 1 dieksekusi, benang anak 2 bangun di utas utama, dan utas utama membangunkan benang anak 1. Mekanisme bangunnya mirip dengan buffer di atas. Mari kita lihat kode di bawah ini, mudah dimengerti.
Kelas publik threeConditionCommunication {public static void main (string [] args) {bisnis bisnis = bisnis baru (); utas baru (runnable baru () {// buka thread anak @override public void run () {for (int i = 1; i <= 50; i ++) {bussiness.sub1 (i) (i); {// Mulailah utas anak lain @Override public void run () {for (int i = 1; i <= 50; i ++) {bussiness.sub2 (i);}}}). Start (); // Metode utama utas utama untuk (int i = 1; i <= 50; i ++) {locksiness.main (i); Reentrantlock (); kondisi kondisi1 = lock.newcondition (); // kondisi adalah suatu kondisi2 = lock.newcondition (); condition conditionmain = lock.newcondition (); inter private int bshouldsub = 0; public void sub1 (int i) {lock.lock (); coba {whilouldsub! Metode Await} catch (Exception e) {// TODO Auto-Eynerated Catch Blocke.PrintStackTrace ();}} untuk (int j = 1; j <= 10; j ++) {System.out.println ("Sub1 Thread Sequence of" + J + ", loop dari" + i);} Bshouldsubs = 1; {lock.unlock ();}} public void sub2 (int i) {lock.lock (); coba {while (bshouldsub! = 1) {coba {condition2.Await (); // Kondisi Gunakan untuk menyebut metode AWait} (Exception e) {// TODO Auto-Generated Catch Blocke.printsprint. j ++) {System.out.println ("Urutan utas sub2" + j + ", loop" + i);} bshouldsub = 2; conditionmain.signal (); // biarkan utas utama dieksekusi} akhirnya {lock.unlock ();}} public void main (int i) {lock.lock (lock.unlock (); {conditionmain.aWait (); // Gunakan kondisi untuk memanggil metode menunggu} catch (pengecualian e) {// TODO TODO AUTO-EKSIRED Catch blocke.printstacktrace ();}} for (int j = 1; j <= 5; j ++) {System.out.println ("Urutan utama utas utama dari" + J + J ++ " 0; condition1.signal (); // biarkan utas 1 dieksekusi} akhirnya {lock.unlock ();}}}}Kode tampaknya agak panjang, tetapi itu adalah ilusi dan logikanya sangat sederhana. Itu saja untuk meringkas teknologi kondisi di utas.
Di atas adalah seluruh konten artikel ini tentang contoh kode aplikasi dari kondisi pemblokiran kondisi konkurensi Java. Saya harap ini akan membantu semua orang. Teman yang tertarik dapat terus merujuk ke topik terkait lainnya di situs ini. Jika ada kekurangan, silakan tinggalkan pesan untuk menunjukkannya. Terima kasih teman atas dukungan Anda untuk situs ini!