Panduan untuk PriorityBlockingQueue di Java

1. Perkenalan

Dalam artikel ini, kita akan fokus pada kelas PriorityBlockingQueue dan membahas beberapa contoh praktis.

Dimulai dengan asumsi bahwa kita telah mengetahui apa itu Queue , pertama-tama kita akan mendemonstrasikan bagaimana elemen dalam PriorityBlockingQueue diurutkan berdasarkan prioritas .

Setelah ini, kami akan mendemonstrasikan bagaimana jenis antrian ini dapat digunakan untuk memblokir sebuah utas.

Terakhir, kami akan menunjukkan bagaimana menggunakan kedua fitur ini bersama-sama dapat berguna saat memproses data di beberapa utas.

2. Prioritas Elemen

Tidak seperti antrian standar, Anda tidak bisa hanya menambahkan jenis elemen apa pun ke PriorityBlockingQueue. Ada dua pilihan:

  1. Menambahkan elemen yang mengimplementasikan Comparable
  2. Menambahkan elemen yang tidak mengimplementasikan Comparable , dengan syarat Anda menyediakan Comparator juga

Dengan menggunakan Comparator atau implementasi Comparable untuk membandingkan elemen, PriorityBlockingQueue akan selalu diurutkan.

Tujuannya adalah untuk mengimplementasikan logika perbandingan dengan cara di mana elemen dengan prioritas tertinggi selalu diurutkan terlebih dahulu . Kemudian, saat kami menghapus elemen dari antrean kami, itu akan selalu menjadi yang memiliki prioritas tertinggi.

Untuk memulainya, mari gunakan antrian kita dalam satu utas, sebagai lawan menggunakannya di banyak utas. Dengan melakukan ini, memudahkan untuk membuktikan bagaimana elemen diurutkan dalam pengujian unit:

PriorityBlockingQueue queue = new PriorityBlockingQueue(); ArrayList polledElements = new ArrayList(); queue.add(1); queue.add(5); queue.add(2); queue.add(3); queue.add(4); queue.drainTo(polledElements); assertThat(polledElements).containsExactly(1, 2, 3, 4, 5);

Seperti yang bisa kita lihat, meskipun menambahkan elemen ke antrian dalam urutan acak, mereka akan diurutkan ketika kita mulai melakukan polling. Ini karena kelas Integer mengimplementasikan Comparable, yang pada gilirannya akan digunakan untuk memastikan kami mengeluarkannya dari antrean dalam urutan menaik.

Perlu juga dicatat bahwa ketika dua elemen dibandingkan dan sama, tidak ada jaminan bagaimana mereka akan diurutkan.

3. Menggunakan Antrian untuk Memblokir

Jika kita berurusan dengan antrian standar, kita akan memanggil poll () untuk mengambil elemen. Namun, jika antrian kosong, panggilan ke poll () akan mengembalikan null.

The PriorityBlockingQueue alat yang BlockingQueue antarmuka, yang memberi kami beberapa metode tambahan yang memungkinkan kita untuk memblokir saat melepas dari antrian kosong . Mari kita coba menggunakan metode take () , yang seharusnya melakukan persis seperti itu:

PriorityBlockingQueue queue = new PriorityBlockingQueue(); new Thread(() -> { System.out.println("Polling..."); try { Integer poll = queue.take(); System.out.println("Polled: " + poll); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); Thread.sleep(TimeUnit.SECONDS.toMillis(5)); System.out.println("Adding to queue"); queue.add(1);

Meskipun menggunakan sleep () adalah cara yang sedikit rapuh untuk mendemonstrasikan sesuatu, ketika kita menjalankan kode ini kita akan melihat:

Polling... Adding to queue Polled: 1 

Ini membuktikan bahwa take () diblokir hingga item ditambahkan:

  1. Utas akan mencetak "Polling" untuk membuktikan bahwa ini telah dimulai
  2. Tes kemudian akan berhenti selama sekitar lima detik, untuk membuktikan bahwa utas pasti telah memanggil take () pada saat ini
  3. Kami menambahkan ke antrean, dan akan segera melihat "Disurvei: 1" untuk membuktikan bahwa take () mengembalikan elemen segera setelah tersedia

Perlu juga disebutkan bahwa antarmuka BlockingQueue juga memberi kita cara memblokir saat menambahkan ke antrian penuh.

Namun, PriorityBlockingQueue tidak dibatasi. Ini berarti tidak akan pernah penuh, sehingga selalu memungkinkan untuk menambahkan elemen baru.

4. Menggunakan Pemblokiran dan Pembuatan Prioritas Bersama

Sekarang kita telah menjelaskan dua konsep utama dari PriorityBlockingQueue, mari kita gunakan keduanya bersamaan. Kami hanya dapat memperluas contoh kami sebelumnya, tetapi kali ini menambahkan lebih banyak elemen ke antrian:

Thread thread = new Thread(() -> { System.out.println("Polling..."); while (true) { try { Integer poll = queue.take(); System.out.println("Polled: " + poll); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); Thread.sleep(TimeUnit.SECONDS.toMillis(5)); System.out.println("Adding to queue"); queue.addAll(newArrayList(1, 5, 6, 1, 2, 6, 7)); Thread.sleep(TimeUnit.SECONDS.toMillis(1));

Sekali lagi, meskipun ini sedikit rapuh karena penggunaan sleep (), ini masih menunjukkan kasus penggunaan yang valid. Kami sekarang memiliki antrian yang memblokir, menunggu elemen ditambahkan. Kami kemudian menambahkan banyak elemen sekaligus, dan kemudian menunjukkan bahwa mereka akan ditangani dalam urutan prioritas. Outputnya akan terlihat seperti ini:

Polling... Adding to queue Polled: 1 Polled: 1 Polled: 2 Polled: 5 Polled: 6 Polled: 6 Polled: 7

5. Kesimpulan

Dalam panduan ini, kami telah mendemonstrasikan bagaimana kami dapat menggunakan PriorityBlockingQueue untuk memblokir utas hingga beberapa item telah ditambahkan ke dalamnya, dan kami juga dapat memproses item tersebut berdasarkan prioritasnya.

Penerapan contoh-contoh ini dapat ditemukan di GitHub. Ini adalah proyek berbasis Maven, jadi harus mudah dijalankan apa adanya.