Gunakan tunggu () dan beri tahu () untuk mencapai kolaborasi antar-benih
1. Tunggu () dan beri tahu ()/notifyall ()
Ketika tidur () dan hasil () dipanggil, kunci tidak dilepaskan, dan panggilan tunggu () akan melepaskan kunci. Dengan cara ini tugas lain (utas) dapat memperoleh kunci objek saat ini, sehingga memasukkan metode yang disinkronkan. Anda dapat melanjutkan eksekusi dari tunggu () melalui notify ()/notifyall () atau waktu berakhir.
Tunggu (), notify (), dan notifyAll () hanya dapat dipanggil dalam metode kontrol sinkronisasi atau blok sinkronisasi. Jika metode ini dipanggil dalam metode asinkron, pengecualian IllegalMonitateStateException akan dilemparkan saat runtime.
2. Simulasi bangun beberapa utas dengan satu utas
Simulasi kolaborasi antar utas. Kelas game memiliki 2 metode sinkronisasi persiapan () dan go (). Awal bendera digunakan untuk menentukan apakah utas saat ini perlu tunggu (). Contoh dari kelas game memulai semua instance kelas Athele terlebih dahulu dan masukkan status tunggu (). Setelah periode waktu tertentu, ubah bit bendera dan notifyall () semua utas Athele dalam keadaan tunggu.
Game.java
Paket konkurensi; impor java.util.collection; impor java.util.collections; impor java.util.hashset; impor java.util.iterator; import java.util.set; atlet kelas mengimplementasikan runnable {private final int id; game game pribadi; atlet publik (int id, game game) {this.id = id; this.game = game; } public boolean sama (objek o) {if (! (o instance dari atlet)) mengembalikan false; Atlet atlet = (atlet) o; return id == atlet.id; } public string toString () {return "atlet <" + id + ">"; } public int hashCode () {return new integer (id) .hashCode (); } public void run () {coba {game.prepare (this); } catch (InterruptedException e) {System.out.println (this + "Quit the Game"); }}} Game kelas publik mengimplementasikan runnable {private set <Thlete> pemain = hashset baru <Hlete> (); Private Boolean Start = false; public void addPlayer (atlet satu) {playes.add (satu); } public void Remeplayer (atlet satu) {playes.remove (satu); } Koleksi Publik <Thlete> getPlayers () {return collections.unmodifibleset (pemain); } public void mempersiapkan (atlet atlet) melempar interruptedException {System.out.println (atlet + "Ready!"); disinkronkan (ini) {while (! start) tunggu (); if (start) system.out.println (atlet + "go!"); }} public disinkronkan void go () {notifyAll (); } public void ready () {iterator <Thlete> iter = getplayers (). iterator (); while (iter.hasnext ()) utas baru (iter.next ()). start (); } public void run () {start = false; System.out.println ("Ready ..."); System.out.println ("Ready ..."); System.out.println ("Ready ..."); siap(); mulai = true; System.out.println ("Go!"); pergi(); } public static void main (string [] args) {game game = new game (); untuk (int i = 0; i <10; i ++) game.addplayer (atlet baru (i, game)); utas baru (game) .start (); }} hasil:
Siap ... Siap ... Siap ... Atlet <0> Siap! Atlet <1> Siap! Athlete <2> Siap! Atlet <3> Siap! Atlet <4> Siap! Atlet <5> Atlet <6> Atlet <6> Atlet <7> Siap! Atlet <8> Atlet <9> Pergi! Pergi! GO atlet <9> go! GO! Pergi! Atlet <3> Pergi! Atlet <2> Pergi! Atlet <1> Pergi! Atlet <0> Pergi!
3. Simulasi proses menunggu yang sibuk
Contoh kelas MyObject adalah pengamat. Ketika peristiwa pengamatan terjadi, itu akan memberi tahu contoh kelas monitor (cara mengubah bendera). Contoh kelas monitor ini terus -menerus memeriksa apakah bit flag berubah dengan menunggu.
Busywaiting.java
impor java.util.concurrent.timeunit; kelas myObject implement runnable {monitor privat monitor; MyObject publik (monitor monitor) {this.monitor = monitor; } public void run () {coba {timeunit.seconds.sleep (3); System.out.println ("Aku akan pergi."); monitor.gotmessage (); } catch (InterruptedException e) {E.PrintStackTrace (); }}} monitor kelas mengimplementasikan runnable {private volatile boolean go = false; public void gotsage () melempar InterruptedException {go = true; } public void watching () {while (go == false); System.out.println ("Dia telah pergi."); } public void run () {watchle (); }} kelas publik BusyWaiting {public static void main (string [] args) {monitor monitor = new monitor (); MyObject o = myObject baru (monitor); utas baru (o) .start (); utas baru (monitor) .start (); }} hasil:
Aku akan pergi. Dia telah pergi.
4. Gunakan tunggu () dan beri tahu () untuk menulis ulang contoh di atas
Contoh berikut menggantikan mekanisme menunggu yang sibuk melalui Wait (). Ketika pesan pemberitahuan diterima, beri tahu utas kelas monitor saat ini.
Tunggu.java
paket concurrency.wait; import java.util.concurrent.timeunit; kelas myObject mengimplementasikan runnable {private monitor monitor; MyObject publik (monitor monitor) {this.monitor = monitor; } Mulai utas secara teratur
Berikut adalah dua cara untuk memulai utas setelah waktu yang ditentukan. Pertama, ini diimplementasikan melalui java.util.concurrent.delayqueue; Kedua, diimplementasikan melalui java.util.concurrent.scheduledThreadPoolExecutor.
1. Java.util.concurrent.delayqueue
Kelas Delayqueue adalah antrian pemblokiran yang tidak terbatas dari mana elemen dapat diekstraksi hanya ketika penundaan berakhir. Ia menerima contoh yang menerapkan antarmuka yang tertunda sebagai elemen.
<< Antarmuka >> tertunda.java
Paket java.util.concurrent; import java.util.*; Antarmuka publik tertunda memperluas <Delayed> {long getDelay (unit TimeUnit);}getDelay () Mengembalikan waktu tunda yang tersisa yang terkait dengan objek ini, dinyatakan dalam unit waktu tertentu. Implementasi antarmuka ini harus menentukan metode compareTo yang memberikan jenis yang konsisten dengan metode GetDelay dari antarmuka ini.
Kepala antrian Delayqueue adalah elemen tertunda dengan waktu penyimpanan terpanjang setelah penundaan berakhir. Kedaluwarsa terjadi ketika metode GetDelay (TimeUnit.nanoseconds) dari suatu elemen mengembalikan nilai kurang dari atau sama dengan 0.
2. Desain antrian dengan karakteristik waktu tunda
Kelas DelayedTasker mempertahankan delayqueue <dllayedTask> antrian, di mana DelayDedTask mengimplementasikan antarmuka yang tertunda dan ditentukan oleh kelas internal. Kelas eksternal dan kelas internal mengimplementasikan antarmuka yang dapat dilalui. Untuk kelas eksternal, metode yang dijalankannya mengambil tugas dalam antrian secara berurutan sesuai dengan waktu yang ditentukan, dan tugas -tugas ini adalah contoh kelas internal. Metode run dari kelas internal mendefinisikan logika spesifik dari masing -masing utas.
Inti dari desain ini adalah untuk menentukan daftar tugas utas dengan karakteristik waktu, dan daftarnya bisa panjangnya. Tentukan waktu startup setiap kali Anda menambahkan tugas.
DelayedTasker.java
Paket com.zj.timedtask; impor statis java.util.concurrent.timeunit.seconds; impor statis java.util.concurrent.timeunit.nanoseconds; impor java.util.collection; impor java.util.collection; impor java.collection; java.util.concurrent.delayed; impor java.util.concurrent.executorservice; impor java.util.concurrent.executors; import java.util.concurrent.timeunit; class publicledtasker mengimplementasikan runnable {delayqueue <delayqueue <layedtask> public class delayker <layplement {delayqueue <llayqueue <ludgeDeDask> quuue publicaDeQuDer <dlay loudeQUDEKER <llay loudeQuDer <dll DayDQueue <llayqueE <llayDequeDerker; public void addTask (delayedTask e) {queue.put (e); } public void removeTask () {queue.poll (); } koleksi publik <DeldayedTask> getAllTasks () {return collections.unmodifiaBleCollection (antrian); } public int getTaskQuantity () {return queue.size (); } public void run () {while (! queue.isempty ()) coba {queue.take (). run (); } catch (InterruptedException e) {System.out.println ("Interrupted"); } System.out.println ("Finish DelayDedTask"); } public static class delayedTask mengimplementasikan tertunda, runnable {private static int counter = 0; private final int id = counter ++; Private Final Int Delta; pemicu panjang final pribadi; DelayDedTask publik (int delayinseconds) {delta = delayinseconds; trigger = system.nanoTime () + nanoseconds.convert (delta, detik); } public long getDelay (TimeUnit Unit) {return unit.convert (Trigger - System.nanoTime (), nanoseconds); } public int compareto (Delayed arg) {delayedTask that = (delayedTask) arg; if (pemicu <that.trigger) return -1; if (trigger> that.trigger) return 1; kembali 0; } public void run () {// Jalankan semua yang ingin Anda lakukan system.out.println (ini); } public string toString () {return "[" + delta + "s]" + "Task" + id; }} public static void main (string [] args) {acak rand = new random (); ExecutorService exec = executors.newcachedThreadpool (); DelayedTasker Tasker = new DelayedTasker (); untuk (int i = 0; i <10; i ++) tasker.addtask (new DelayedTask (rand.nextint (5))); exec.execute (Tasker); exec.shutdown (); }} hasil:
[0s] Tugas 1 [0s] Tugas 2 [0s] Tugas 3 [1S] Tugas 6 [2s] Tugas 5 [3S] Tugas 8 [4S] Tugas 0 [4S] Tugas 4 [4S] Tugas 7 [4S] Tugas 9FinishedDelayedTask
3. java.util.concurrent.scheduledThreadPoolExecutor
Kelas ini dapat dijadwalkan untuk menjalankan tugas (utas) setelah penundaan yang diberikan, atau untuk melakukan tugas secara teratur (ulangi). Di konstruktor, Anda perlu mengetahui ukuran kumpulan benang. Metode utama adalah:
[1] Jadwal
jadwal jadwal publik <?> (perintah runnable, penundaan lama, unit timeunit)
Membuat dan melakukan operasi satu kali diaktifkan setelah penundaan yang diberikan.
Ditunjuk oleh:
- Jadwal antarmuka yang dijadwalkan ExcecutorService;
parameter:
-Kommand - tugas yang harus dilakukan;
-delay - Waktu untuk menunda eksekusi mulai sekarang;
-unit - unit waktu parameter penundaan;
kembali:
- Menunjukkan jadwal yang dijadwalkan yang menangguhkan tugas dan metode get () akan mengembalikan nol setelah selesai.
[2] JadwalFixEdrate
Publik TerjadwalFuture <?> SCECTULULEATFIXEDRATE (
Perintah runnable, inisial panjang, periode panjang, unit timeunit)
Membuat dan menjalankan operasi periodik yang pertama kali diaktifkan setelah penundaan awal yang diberikan, dengan operasi selanjutnya memiliki periode tertentu; Artinya, itu akan dimulai setelah InitialDelay, kemudian setelah periode InitialDelay +, kemudian setelah inisialdelay + 2 * periode, dan seterusnya. Jika ada pelaksanaan tugas yang menemukan pengecualian, eksekusi selanjutnya akan dibatalkan. Jika tidak, tugas hanya dapat diakhiri dengan melaksanakan metode pembatalan atau penghentian program. Jika salah satu eksekusi tugas ini memakan waktu lebih lama dari siklusnya, eksekusi selanjutnya akan ditunda, tetapi tidak secara bersamaan.
Ditunjuk oleh:
- penjadwalanFixedRate di antarmuka yang dijadwalkan ExcecutorService;
parameter:
-Kommand - tugas yang harus dilakukan;
-InitialDelay - waktu tunda untuk eksekusi pertama;
-Period - Periode antara eksekusi berkelanjutan;
-unit - unit waktu parameter inisial dan periode;
kembali:
- Menunjukkan bahwa jadwal yang dijadwalkan dari tugas yang ditangguhkan selesai, dan metode get () akan melempar pengecualian setelah dibatalkan.
4. Eksekutor Design Thread dengan karakteristik waktu tunda
Class Scheduletasked mengaitkan jadwalThreadPoolExcutor, yang dapat menentukan ukuran kumpulan utas. Ketahui utas dan tunda waktu melalui metode jadwal, dan tutup kumpulan utas melalui metode shutdown. Logika tugas spesifik (utas) memiliki fleksibilitas tertentu (dibandingkan dengan desain sebelumnya, desain sebelumnya harus menentukan logika utas sebelumnya, tetapi desain logika spesifik utas dapat dimodifikasi dengan warisan atau dekorasi).
SCRECTULETASKER.java
Paket com.zj.timedTask; import java.util.concurrent.scheduledThreadPoolExecutor; import java.util.concurrent.timeunit; public class scheduletasker {private int corepoolsize = 10; Jadwal TerjadwalTReadPoolExecutor; public scheduletasker () {scheduler = new StorduledThreadPoolExecutor (corePoolSize); } public scheduletasker (int kuantitas) {corepoolsize = kuantitas; penjadwal = jadwal baru threadpoolexecutor (corePoolsize); } jadwal public void (acara runnable, penundaan lama) {scheduler.schedule (event, delay, timeunit.seconds); } public void shutdown () {scheduler.shutdown (); } public static void main (string [] args) {scheduletasker tasker = new scheduletasker (); tasker.schedule (runnable baru () {public void run () {System.out.println ("[1S] Tugas 1");}}, 1); tasker.schedule (runnable baru () {public void run () {System.out.println ("[2s] Task 2");}}, 2); Tasker.schedule (runnable baru () {public void run () {System.out.println ("[4s] Tugas 3");}}, 4); tasker.schedule (runnable baru () {public void run () {public void run () {System.out.println ("[10s] Tugas 4");}}, 10); tasker.shutdown (); }} hasil:
[1S] Tugas 1 [2s] Tugas 2 [4S] Tugas 3 [10s] Tugas 4 public void run () {coba {timeunit.seconds.sleep (3); System.out.println ("Aku akan pergi."); monitor.gotmessage (); } catch (InterruptedException e) {E.PrintStackTrace (); }}} Monitor kelas mengimplementasikan runnable {private volatile boolean go = false; void gotsage yang disinkronkan publik () melempar InterruptedException {go = true; memberitahu(); } public yang disinkronkan void watching () melempar interruptedException {while (go == false) tunggu (); System.out.println ("Dia telah pergi."); } public void run () {coba {watchle (); } catch (InterruptedException e) {E.PrintStackTrace (); }}} kelas publik tunggu {public static void main (string [] args) {monitor monitor = new monitor (); MyObject o = myObject baru (monitor); utas baru (o) .start (); utas baru (monitor) .start (); }} hasil:
Aku akan pergi. Dia telah pergi.