Pola konsumen produsen adalah pola yang paling umum di antara multi-threading: utas produsen (satu atau lebih) menghasilkan roti dan memasukkannya ke dalam keranjang (set atau array), dan pada saat yang sama, utas konsumen (satu atau lebih) mengeluarkan roti dari keranjang (set atau array) dan mengkonsumsinya. Meskipun mereka memiliki tugas yang berbeda, sumber daya yang mereka proses adalah sama, yang mencerminkan metode komunikasi antar-utas.
Artikel ini pertama-tama akan menjelaskan situasi produsen tunggal dan konsumen tunggal, dan kemudian menjelaskan situasi model multi-produser dan multi-konsumen. Kedua mode ini juga akan diimplementasikan menggunakan mekanisme tunggu ()/nofity ()/noFityAll () dan mekanisme kunci ()/buka kunci () masing -masing.
Sebelum memulai pengenalan pola, jelaskan rincian penggunaan metode tunggu (), notify () dan notifyall () serta penggunaan lock ()/buka (), waait ()/sinyal ()/sinyal ().
1. Prinsip Mekanisme Menunggu dan Bangun
tunggu (), beri tahu () dan notifyAll () masing -masing mewakili utas yang masuk tidur, bangunkan benang tidur, dan bangun semua benang tidur. Tapi, utas mana objeknya? Selain itu, ketiga metode yang dijelaskan dalam dokumentasi API harus digunakan di bawah premis monitor yang valid (yang dapat dipahami sebagai memegang kunci). Apa hubungan ketiga metode ini dengan mengunci?
Mengambil blok kode sinkronisasi disinkronkan (OBJ) {} atau fungsi sinkronisasi sebagai contoh, tunggu (), notify (), dan notifyall () dapat digunakan dalam struktur kode mereka karena mereka semua memegang kunci.
Untuk dua blok kode sinkronisasi berikut, kunci OBJ1 dan LOCK OBJ2 masing -masing digunakan. Thread 1 dan Thread 2 menjalankan kode sinkronisasi yang sesuai dengan OBJ1, dan Thread 3 dan Thread 4 menjalankan kode sinkronisasi yang sesuai dengan OBJ2.
kelas mylock mengimplementasikan runnable {public int flag = 0; Objek obj1 = objek baru (); Objek obj2 = objek baru (); public void run () {while (true) {if (flag%2 = 0) {disinkronkan (obj1) {// thread T1 dan t2 melakukan tugas sinkronisasi ini // coba {obj1.wait ();} catch (interruptedException i) {} //obj1.notify ()///interruptException I) {} //obj1.notify ()///{notify () {{} //obj1.notify () /////// /// /// /// /// /// ///erobol () (). disinkronkan (obj2) {// thread t3 dan t4 lakukan tugas sinkronisasi ini // coba {obj2.wait ();} catch (interruptedexception i) {} //obj2.notify () //obj2.notifyAll ()}}}}}}}} {notifyall {) {noifyall {) {notify {notify {notify {notify {notify {notify {notify {notify {notify {notify {notify {notify ml = mylock baru (); Utas T1 = utas baru (ml); Utas T2 = utas baru (ml); Utas T3 = utas baru (ml); Utas T4 = utas baru (ml); t1.start (); t2.start (); coba {thread.sleep (1)} catch (InterruptedException i) {}; ml.flag ++; t3.start (); t4.start (); }}Ketika T1 mulai mengeksekusi untuk menunggu (), itu akan memasuki keadaan tidur, tetapi itu bukan tidur normal, tetapi tidur di kolam benang yang diidentifikasi oleh OBJ1 (sebenarnya monitor sesuai dengan kumpulan utas, tetapi monitor dan kunci diikat bersama pada saat ini). Ketika T2 mulai mengeksekusi, ia menemukan bahwa Lock OBJ1 dipegang oleh utas lain dan akan memasuki keadaan tidur. Kali ini karena sumber daya kunci menunggu daripada tidur yang dimasukkan oleh Wait (). Karena T2 telah menentukan bahwa ia berlaku untuk kunci OBJ1, itu juga akan memasuki tidur benteng OBJ1, daripada tidur biasa. Demikian pula, T3 dan T4, kedua utas ini akan memasuki kolam benang OBJ2 untuk tidur.
Ketika utas dieksekusi untuk memberi tahu (), ini notify () akan secara acak membangunkan utas apa pun di kumpulan utas yang sesuai dengan kuncinya. Misalnya, obj1.notify () akan membangunkan benang tidur apa pun di kolam benang OBJ1 (tentu saja, jika tidak ada benang tidur, maka tidak melakukan apa -apa). Demikian pula, NotifyAll () membangunkan semua benang tidur di kumpulan benang kunci yang sesuai.
Apa yang harus Anda cari tahu adalah "kunci yang sesuai", karena kunci harus ditentukan secara eksplisit saat menelepon tunggu (), notify () dan notifyall (). Misalnya, obj1.wait (). Jika kunci miliknya dihilangkan, itu berarti objek ini, yaitu, awalan dari ketiga metode ini hanya dapat dihilangkan dalam fungsi sinkronisasi non-statis.
Singkatnya, ketika sinkronisasi digunakan, kunci digunakan, dan utas memiliki rumah, dan semua dasarnya ditentukan oleh kunci milik. Misalnya, ketika sinkronisasi utas, itu menentukan apakah kunci menganggur untuk memutuskan apakah akan menjalankan kode selanjutnya, dan juga menentukan apakah akan pergi ke kumpulan utas tertentu untuk tidur. Saat bangun, itu hanya akan membangunkan utas di kumpulan benang yang sesuai dengan kunci.
Dalam penerapan metode ini, umumnya dalam tugas, tunggu () dan notify ()/notifyall () muncul berpasangan dan jalankan satu per satu. Dengan kata lain, selama putaran eksekusi sinkron atom ini, baik tunggu () dieksekusi untuk tidur, atau notify () dieksekusi untuk membangunkan benang tidur di kolam benang. Untuk mencapai eksekusi selektif, Anda dapat mempertimbangkan untuk menggunakan penandaan sebagai dasar penilaian. Lihat contoh -contoh berikut.
2. Kunci dan Kondisi
Tiga metode dari seri Wait () sangat terbatas karena kedua tindakan tidur dan bangun sepenuhnya digabungkan dengan kunci. Misalnya, utas yang terkait dengan kunci OBJ1 hanya dapat membangunkan utas di kumpulan utas OBJ1, tetapi tidak dapat membangunkan utas yang terkait dengan kunci OBJ2; Sebagai contoh, ketika sinkronisasi yang disinkronkan pada awalnya disinkronkan, kunci secara implisit secara otomatis diperoleh ketika sinkronisasi dimulai, dan setelah seluruh tugas dieksekusi, secara implisit secara otomatis melepaskan kunci, yang berarti bahwa tindakan memperoleh kunci dan melepaskan kunci tidak dapat dikendalikan secara manual.
Mulai dari JDK 1.5, Java menyediakan paket java.util.concurrent.locks, yang menyediakan antarmuka kunci, antarmuka kondisi dan antarmuka ReadWritelock. Dua antarmuka pertama memisahkan metode kunci dan monitor (tidur, operasi bangun). Antarmuka kunci hanya menyediakan kunci. Melalui metode kunci newconditon (), satu atau lebih monitor yang terkait dengan kunci dapat dihasilkan. Setiap monitor memiliki metode tidur dan bangun sendiri. Dengan kata lain, kunci menggantikan penggunaan metode yang disinkronkan dan blok kode yang disinkronkan, dan kondisi menggantikan penggunaan metode monitor objek.
Seperti yang ditunjukkan pada gambar di bawah ini:
Ketika utas mengeksekusi condition1.Await (), utas akan memasukkan kumpulan utas yang sesuai dengan monitor Condition1 untuk tidur. Ketika condition1.signal () dieksekusi, utas apa pun di kumpulan benang Condition1 akan dibangunkan secara acak. Ketika condition1.signalall () dieksekusi, semua utas di kumpulan benang Condition1 akan dibangunkan. Demikian pula, hal yang sama berlaku untuk monitor Condition2.
Bahkan jika ada beberapa monitor, selama mereka dikaitkan dengan objek kunci yang sama, utas lainnya dapat dioperasikan di seluruh monitor. Misalnya, utas di Condition1 dapat menjalankan condition2.signal () untuk membangunkan utas di kumpulan benang Condition2.
Untuk menggunakan cara asosiasi kunci dan monitor ini, lihat langkah -langkah berikut:
Impor java.util.concurrent.locks.*; lock l = baru reentrantlock (); kondisi con1 = l.newcondition (); kondisi con2 = l.newcondition (); l.lock (); coba {// Segmen kode yang mengandung waait (), sinyal () atau sinyal () ...} akhirnya {). // Karena segmen kode mungkin abnormal, buka kunci () harus dieksekusi, coba harus digunakan dan buka kunci () harus dimasukkan ke dalam segmen akhirnya}Untuk penggunaan tertentu, silakan lihat kode contoh untuk kunci dan kondisi nanti.
3. Model konsumen tunggal produsen tunggal
Utas produsen, utas konsumen. Untuk setiap roti yang diproduksi oleh produsen, letakkan di atas piring, konsumen mengeluarkan roti dari piring untuk dikonsumsi. Dasar bagi produsen untuk menilai apakah akan melanjutkan produksi adalah bahwa tidak ada roti di piring, sementara dasar bagi konsumen untuk menilai apakah akan mengkonsumsi adalah bahwa ada roti di piring. Karena dalam mode ini, hanya satu roti roti yang selalu ditempatkan di atas piring, piring dapat dihilangkan dan produsen dan konsumen dapat menyerahkan roti selangkah demi selangkah.
Pertama, kita perlu menggambarkan ketiga kategori ini: satu adalah sumber daya yang dioperasikan oleh banyak utas (di sini adalah roti), yang kedua adalah produsen, dan yang ketiga adalah konsumen. Dalam contoh berikut, saya merangkum metode memproduksi roti dan mengonsumsi roti ke kelas produsen dan konsumen, yang lebih mudah dipahami jika mereka dienkapsulasi dalam kelas roti.
// Deskripsi Sumber Daya: Nama dan jumlah roti, ditentukan oleh jumlah roti kelas roti {nama string publik; Hitungan int publik = 1; bendera boolean publik = false; // Tanda ini memberikan tanda penilaian untuk tunggu () dan notify ()} // sumber daya roti yang diproses oleh produsen dan konsumen sama. Untuk memastikan ini, // Kelas roti dapat dirancang sesuai dengan pola singleton, atau objek roti yang sama dapat diteruskan ke produsen dan konsumen melalui metode konstruksi. Metode terakhir digunakan di sini. // Jelaskan produser produser produser mengimplementasikan runnable {private bread b; // anggota produser: sumber daya yang ingin diproses produser (roti b) {this.b = b; } // Memberikan metode untuk memproduksi roti public void (nama string) {b.name = name + b.count; B.Count ++; } public void run () {while (true) {disinkronkan (bread.class) {// Gunakan bread.class sebagai pengidentifikasi kunci sehingga blok kode yang disinkronkan dari produsen dan konsumen dapat menggunakan kunci yang sama jika terkunci (b.flag) {// tunggu () harus ada di dalam blok kode yang sinkron, bukan hanya kunci yang harus diadakan di dalam blok kode yang disinkron coba {bread.class.wait ();} catch (InterruptedException i) {}} produce ("Bread"); System.out.println (thread.currentThread (). GetName ()+"---------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // notify () juga harus disinkronkan, jika tidak kunci telah dirilis, dan tindakan bangun tidak dapat dilakukan // PS: dalam tugas sinkronisasi, tunggu () dan notify () hanya boleh dieksekusi, jika tidak, Posisi Konsumsi Konsumen akan dikeluarkan {Sumber Daya Konsumen. this.b = b;} // Metode penyediaan konsumsi konsumsi publik () {return b.name; System.out.println(Thread.currentThread().getName()+"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- /2.Hasil eksekusi akhir harus diproduksi dan dikonsumsi, dan ini adalah siklus kontinu. sebagai berikut:
Thread-0---Producer----Bread1Thread-1---Consumer-------Bread1Thread-0---Producer----Bread2Thread-1--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4. Gunakan kunci dan kondisi untuk mewujudkan model produksi dan konsumsi tunggal
Kodenya adalah sebagai berikut:
impor java.util.concurrent.locks.*; class bread {public string name; Hitungan int publik = 1; bendera boolean publik = false; // Berikan objek kunci yang sama dan objek kondisi yang sama untuk produsen dan konsumen kunci kunci statis publik = reentrantlock baru (); kondisi statis public kondisi = lock.newcondition ();} produser kelas mengimplementasikan runnable {private bread b; Produser (roti b) {this.b = b; } public void produk (nama string) {b.name = name + b.count; B.Count ++; } public void run () {while (true) {// Gunakan bread.lock untuk mengunci sumber daya roti.lock.lock (); coba {if (b.flag) {coba {bread.condition.await ();} catch (interruptedException i) {}} menghasilkan ("roti"); System.out.println (thread.currentThread (). GetName ()+"-------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Bread.condition.signal (); Coba {if (! B.flag) {coba {bread.condition.await ();} catch (InterruptedException i) {}} System.out.println (thread.currentThread (). GetName ()+"---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- /2.5. Model multi-produksi dan konsumsi (roti tunggal)
Di sini kami pertama -tama menjelaskan model banyak produsen dan banyak konsumen, tetapi paling banyak satu roti pada saat yang sama. Model ini mungkin tidak ideal dalam kenyataan, tetapi untuk mengarah pada model multi-produksi dan konsumsi ganda yang nyata kemudian, saya pikir perlu untuk menjelaskan model ini di sini dan menganalisis model ini dan bagaimana ia berevolusi dari kode tunggal dan kode konsumsi tunggal.
Seperti yang ditunjukkan pada gambar di bawah ini:
Dari produksi tunggal dan konsumsi tunggal hingga beberapa produksi dan konsumsi ganda, karena masalah keselamatan multi-utas dan masalah kebuntuan, ada dua masalah yang perlu dipertimbangkan:
Untuk satu pihak, bagaimana multi-threading dapat mencapai produksi atau kapasitas konsumsi yang sama dengan satu threading? Dengan kata lain, cara membuat multi-threading terlihat satu threading. Perbedaan terbesar antara multi-threading dan single-threading adalah masalah keselamatan multi-threading. Oleh karena itu, selama Anda memastikan bahwa tugas yang dieksekusi dengan multi-threading dapat disinkronkan.
Pertanyaan pertama mempertimbangkan masalah multi-threading pada satu pihak, dan pertanyaan kedua mempertimbangkan bagaimana kedua pihak dapat bekerja sama secara harmonis untuk menyelesaikan produksi dan konsumsi. Artinya, bagaimana memastikan bahwa satu sisi produsen dan konsumen sedang tidur saat sisi lain aktif. Bangun saja pihak lain ketika satu pihak telah selesai melakukan tugas sinkronisasi.
Bahkan, dari utas tunggal ke multi-threading, ada dua masalah yang perlu dipertimbangkan: out-of-sinkronisasi dan kebuntuan. (1) Ketika produsen dan sisi konsumen memiliki multi-thread, multi-threads produser dapat dianggap sebagai utas secara keseluruhan, dan multi-thread sisi konsumen juga secara keseluruhan, yang memecahkan masalah keamanan utas. (2) Menggabungkan seluruh produksi dan seluruh konsumen dianggap multi-threading untuk menyelesaikan masalah kebuntuan. Cara untuk menyelesaikan kebuntuan di Jawa adalah membangunkan pihak lain atau membangunkan semuanya.
Pertanyaannya adalah bagaimana memastikan sinkronisasi antara beberapa utas pihak tertentu? Kode konsumen tunggal dianalisis dengan eksekusi multi-threaded sebagai contoh.
while (true) {disinkronkan (bread.class) {if (! b.flag) {coba {bread.class.wait ();} catch (InterruptedException i) {}} System.out.println(Thread.currentThread().getName()+"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Misalkan Thread Konsumsi 1 Bangun Up Konsumsi Thread 2 Setelah mengonsumsi sepotong roti, dan terus mengulang, menilai jika (! Bendera), itu akan menunggu, dan kuncinya dilepaskan. Dengan asumsi bahwa CPU hanya memilih Consumer Thread 2, Consumer Thread 2 juga akan masuk menunggu. Ketika produsen memproduksi sepotong roti, anggaplah bahwa konsumsi utas 1 terbangun, ia akan terus mengonsumsi roti yang baru diproduksi dari pernyataan tunggu, anggaplah bahwa Thread Konsumsi 2 terbangun lagi. Ketika Thread Konsumsi 2 dipilih oleh CPU, Thread Konsumsi 2 juga akan mengkonsumsi ke bawah dari pernyataan tunggu, dan roti yang baru saja diproduksi dikonsumsi. Masalahnya muncul lagi. Benang konsumsi yang terus terbangun 1 dan 2 mengonsumsi roti yang sama, yang berarti roti itu berulang kali dikonsumsi. Ini adalah masalah out-sync multi-threaded lainnya.
Setelah membicarakannya untuk waktu yang lama, sebenarnya sangat mudah dianalisis setelah memperbesar garis pandang. Selama dua atau lebih utas dari satu pihak menunggu penilaian B.Flag, maka dua atau lebih utas dapat terus terbangun dan terus diproduksi atau dikonsumsi ke bawah. Ini menciptakan masalah multi-threading out-sinkronisasi.
Masalah rasa tidak aman terletak pada kenyataan bahwa banyak utas pada pihak yang sama terus menghasilkan atau mengkonsumsi ke bawah setelah kebangkitan terus menerus. Ini disebabkan oleh pernyataan IF. Jika utas tunggu dapat kembali untuk menentukan apakah B.Flag benar setelah bangun, itu dapat membuatnya memutuskan apakah akan terus menunggu atau produksi atau konsumsi ke bawah.
Anda dapat mengganti pernyataan IF dengan pernyataan sementara untuk memenuhi persyaratan. Dengan cara ini, terlepas dari apakah beberapa utas pada pihak tertentu terus terbangun, mereka akan kembali ke Hakim B.Flag.
while (true) {disinkronkan (bread.class) {while (! b.flag) {coba {bread.class.wait ();} catch (InterruptedException i) {}} System.out.println(Thread.currentThread().getName()+"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Masalah keselamatan multithready pertama diselesaikan, tetapi masalah kebuntuan terjadi. Ini mudah dianalisis. Produsen dianggap secara keseluruhan dan konsumen juga merupakan keseluruhan. Ketika utas produsen semua menunggu (utas pesta produksi terus terbangun, semua utas partai akan menunggu), dan konsumen juga menunggu, dan kebuntuan akan muncul. Bahkan, jika Anda melihatnya dengan cara yang diperkuat, produsen dan konsumen dianggap masing -masing sebagai satu utas. Kedua utas ini membentuk beberapa utas. Ketika satu sisi menunggu dan tidak bisa membangunkan sisi lain, sisi lain pasti akan menunggu, jadi itu akan menemui jalan buntu.
Untuk masalah kebuntuan antara kedua belah pihak, selama Anda memastikan bahwa pihak lain dapat dibangunkan, daripada kebangkitan satu pihak yang terus menerus, itu dapat diselesaikan. Cukup gunakan notifyall () atau sinyalAll (), atau Anda dapat membangunkan utas lain melalui sinyal () untuk menyelesaikan masalah. Lihat kode kedua di bawah ini.
Menurut analisis di atas, jika kode produksi tunggal dan model konsumsi tunggal ditingkatkan, itu dapat diubah menjadi model roti tunggal multi-produksi dan multi-konsumsi.
// Segmen Kode 1 Roti Kelas {Nama String Publik; Hitungan int publik = 1; bendera boolean publik = false; } // Jelaskan produser produser produser mengimplementasikan runnable {private bread b; Produser (roti b) {this.b = b; } public void produk (nama string) {b.name = name + b.count; B.Count ++; } public void run () {while (true) {disinkronkan (bread.class) {while (b.flag) {coba {bread.class.wait ();} catch (interruptedException i) {}} produk ("bread"); System.out.println(Thread.currentThread().getName()+"--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- String consumption () {return b.name;} public void run () {while (true) {disinkronkan (bread.class) {while (! B.flag) {coba {bread.class.wait ();} catch (InterruptedException i) {}} System.out.println (thread.currentThread (). GetName ()+"-------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- } Kelas publik ProduceConsume_5 {public void main (string [] args) {// 1 2 Thread con_t1 = con);Berikut ini adalah kode refactored menggunakan kunci dan conditon, menggunakan sinyal () untuk membangunkan utas lainnya.
// Segmen Kode 2Import java.util.concurrent.locks.*; Class bread {name public string; Hitungan int publik = 1; bendera boolean publik = false; kunci kunci statis publik = reentrantlock baru (); Kondisi statis publik pro_con = lock.newcondition (); Kondisi statis publik con_con = lock.newcondition ();} // Jelaskan produser produser produser mengimplementasikan runnable {private bread b; Produser (roti b) {this.b = b; } public void produk (nama string) {b.name = name + b.count; B.Count ++; } public void run () {while (true) {bread.lock.lock (); coba {while (b.flag) {coba {bread.pro_con.await ();} catch (interruptedException i) {}} produk ("roti"); System.out.println (thread.currentThread (). GetName ()+"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Bread.con_con.signal (); Bread.lock.lock (); coba {while (! B.flag) {coba {bread.con_con.await ();} catch (InterruptedException i) {}} System.out.println (thread.currentThread (). GetName ()+"---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- //2. Create producer and consumer objects Producer pro = new Producer(b); Consumer con = new Consumer(b); //3. Create thread object Thread pro_t1 = new Thread(pro); Thread pro_t2 = new Thread(pro); Thread con_t1 = new Thread(con); Thread con_t2 = new Thread(con); pro_t1.start(); pro_t2.start(); con_t1.start(); con_t2.start ();Mari kita ringkas masalah lebih banyak produksi dan lebih banyak konsumsi:
(1). Solusi untuk sinkronisasi multi-threading dari pihak tertentu adalah menggunakan sementara (bendera) untuk menentukan apakah menunggu;
(2). Solusi untuk masalah kebuntuan kedua belah pihak adalah membangunkan pihak lain. Anda dapat menggunakan metode notifyall (), SignalAll () atau sinyal () dari monitor pihak lain.
6. Lebih banyak model produksi dan konsumsi
Ada beberapa utas produsen dan beberapa utas konsumen. Produsen memasukkan roti yang diproduksi ke dalam keranjang (set atau array), dan konsumen mengeluarkan roti dari keranjang. Dasar bagi produsen untuk menilai produksi lanjutan adalah bahwa keranjang penuh, dan dasar bagi konsumen untuk menilai konsumsi yang berkelanjutan adalah apakah keranjang kosong. Selain itu, ketika konsumen mengeluarkan roti, posisi yang sesuai menjadi kosong lagi, dan produsen dapat kembali dan melanjutkan produksi dari posisi awal keranjang, yang dapat dicapai dengan mengatur ulang pointer keranjang.
Dalam model ini, selain menggambarkan produsen, konsumen, dan roti, juga perlu untuk menggambarkan wadah keranjang. Misalkan sebuah array digunakan sebagai wadah, setiap kali produsen menghasilkan satu, pointer produksi bergeser ke belakang, dan setiap kali konsumen mengonsumsi satu, pointer konsumsi bergeser ke belakang.
Kode ini adalah sebagai berikut: Anda dapat merujuk pada contoh kode yang diberikan di kelas API-> Condition
impor java.util.concurrent.locks.*; keranjang kelas {roti pribadi [] arr; // ukuran keranjang keranjang (ukuran int) {arr = roti baru [ukuran]; } // Pointer dari Int and Out Private Int In_ptr, Out_Ptr; // Berapa banyak roti yang tersisa di keranjang pribadi yang tersisa; kunci kunci pribadi = reentrantlock baru (); kondisi pribadi penuh = lock.newcondition (); kondisi pribadi kosong = lock.newcondition (); // roti ke dalam keranjang public void in () {lock.lock (); Coba {while (kiri == arr.length) {coba {full.await ();} catch (interruptedException i) {i.printstacktrace ();}} arr [in_ptr] = roti baru ("mianbao", produser.num ++); System.out.println ("Letakkan roti:"+arr [in_ptr] .getName ()+"------- ke dalam keranjang ["+in_ptr+"]"); Kiri ++; if (++ in_ptr == arr.length) {in_ptr = 0;} empt.signal (); } akhirnya {lock.unlock (); }} // roti keluar dari keranjang roti publik out () {lock.lock (); coba {while (kiri == 0) {coba {empt.await ();} catch (interruptedException i) {i.printstacktrace ();}} roti out_bread = arr [out_ptr]; System.out.println ("Dapatkan roti:"+out_bread.getname ()+"---------- dari keranjang ["+out_ptr+"]"); kiri--; if (++ out_ptr == arr.length) {out_ptr = 0;} full.signal (); kembali out_bread; } akhirnya {lock.unlock (); }}} class bread {private string name; Bread (nama string, int num) {this.name = name + num; } public string getName () {return this.name; }} kelas produser mengimplementasikan runnable {private keranjang keranjang; Public static int num = 1; // Nomor pertama untuk produsen nama roti (keranjang b) {this.basket = b; } public void run () {while (true) {keranjang.in (); Coba {thread.sleep (10);} catch (InterruptedException i) {}}}} kelas konsumen mengimplementasikan runnable {private keranjang keranjang; roti pribadi i_get; Konsumen (keranjang b) {this.basket = b; } public void run () {while (true) {i_get = keranjang.out (); Coba {thread.sleep (10);} catch (InterruptedException i) {}}}} kelas publik ProduceConsume_7 {public static void main (string [] args) {keranjang b = keranjang baru (20); // Ukuran keranjang = 20 produser Pro = produser baru (b); Konsumen con = konsumen baru (b); Thread pro_t1 = utas baru (Pro); Utas pro_t2 = utas baru (Pro); Utas con_t1 = utas baru (con); Utas con_t2 = utas baru (con); Thread con_t3 = utas baru (con); pro_t1.start (); pro_t2.start (); con_t1.start (); con_t2.start (); con_t3.start (); }}Ini melibatkan konsumen, produsen, roti dan keranjang, di mana roti dan keranjang adalah sumber daya yang dioperasikan oleh banyak utas. Benang produsen menghasilkan roti dan memasukkannya ke dalam keranjang, dan benang konsumen mengeluarkan roti dari keranjang. Kode yang ideal adalah merangkum tugas produksi dan tugas konsumsi di kelas sumber daya. Karena roti adalah elemen dari wadah keranjang, tidak cocok untuk dikemas ke dalam kelas roti, dan pengemasan ke dalam keranjang membuatnya lebih mudah untuk mengoperasikan wadah.
Perhatikan bahwa Anda harus meletakkan semua kode yang melibatkan operasi sumber daya di dalam kunci, jika tidak masalah sinkronisasi multi-threaded akan terjadi. Sebagai contoh, metode yang menghasilkan roti didefinisikan dalam kelas produsen, dan kemudian digunakan sebagai parameter dari metode keranjang.in () dimasukkan ke dalam keranjang, mis., Keranjang.in (produser ()), yang merupakan perilaku yang salah karena produser () diteruskan ke metode in () setelah dieksekusi di luar kunci.
Artikel di atas didasarkan pada produser Java dan model konsumen (analisis terperinci) dan merupakan seluruh konten yang dibagikan oleh editor. Saya harap ini dapat memberi Anda referensi dan saya harap Anda dapat mendukung wulin.com lebih lanjut.