Jak używać kolekcji LinkedBlockingQueue?
Kolekcja LinkedBlockingQueue
Kolekcji używamy, gdy chcemy przekazać dużą ilość tekstu lub bardzo duże obiekty (np. obrazy), które nie zmieściłyby się jednorazowo w pamięci albo niepotrzebnie obciążałyby pamięć.
Im większe obiekty tym mniej elementów powinno się jednocześnie znajdować w kolekcji
W moim rozwiązaniu używam czterech klas:
Komunikat.java
– klasa opisująca obiekt przekazywanyNadawca.java
– klasa tworząca i przekazująca komunikatyPrinter.java
– klasa odbierająca obiekty i w naszym przypadku wypisująca komunikaty na konsoliMain.java
– klasa uruchamiająca całość
Kolejka obiektów została ograniczona do 20 komunikatów.
Klasy
Komunikat.java
package blockqueue; public class Komunikat { private String komunikat; public void setKomunikat(String text) { this.komunikat = text; } public String getKomunikat() { return komunikat; } @Override public String toString() { return komunikat; } }
Nadawca.java
package blockqueue; import java.io.*; import java.util.*; import java.util.concurrent.*; public class Nadawca implements Runnable { private final LinkedBlockingQueue<Komunikat> lbq; private final ArrayList<String> als; private int i; private boolean done; Nadawca(LinkedBlockingQueue<Komunikat> lbq) { this.lbq = lbq; String str = read(new File("concurrency/src/assets/Winnetou.txt")); als = tokenize(str); done = false; } @Override public void run() { while (!done) { String temp = als.get(i); if (!temp.equals(null)) { Komunikat komunikat = new Komunikat(); komunikat.setKomunikat(temp); try { lbq.put(komunikat); } catch (InterruptedException e) { e.printStackTrace(); } i++; } else { done = true; } } } /** * Wczytuje plik jako pojedynczy łańcuch znaków * * @return - plik w postaci stringu */ public static String read(File file) { StringBuilder sb = new StringBuilder(); try { try (BufferedReader in = new BufferedReader(new FileReader(file))) { String str; while ((str = in.readLine()) != null) { sb.append(str); } } } catch (IOException ioe) { throw new RuntimeException(ioe); } return sb.toString(); } /** * Tokenizuje string na poszczególne słowa(tokeny) i każde * słowo pisuje do arraylisty * * @param str - string do tokenizacji * @return - kolekcje zawierającą ztokenizowany string */ public static ArrayList<String> tokenize(String str) { ArrayList<String> al = new ArrayList<>(); StringTokenizer st = new StringTokenizer(str, " "); while (st.hasMoreTokens()) { al.add(st.nextToken()); } al.add("###"); return al; } }
Printer.java
package blockqueue; import java.util.concurrent.*; public class Printer implements Runnable { private final LinkedBlockingQueue<Komunikat> lbq; private Komunikat komunikat = null; private boolean notDone; Printer(LinkedBlockingQueue<Komunikat> lbq) { this.lbq = lbq; System.out.println("Drukuję"); notDone = true; } @Override public void run() { while (notDone) { try { komunikat = lbq.take(); } catch (InterruptedException e) { e.printStackTrace(); } String temp = komunikat.getKomunikat(); if (!temp.equals("###")) { System.out.println(temp); } else { System.out.println("Koniec drukowania"); notDone = false; System.exit(0); } } } }
Main.java
package blockqueue; import java.util.concurrent.*; public class Main { public static void main(String[] args) { LinkedBlockingQueue<Komunikat> lbq = new LinkedBlockingQueue<>( 20); Thread t1 = new Thread(new Nadawca(lbq)); Thread t2 = new Thread(new Printer(lbq)); t2.start(); t1.start(); } }
Wynik
Klasa Main
uruchamia aplikację. Tworzona jest kolekcja typu LinkedBlockingQueue
o pojemności 20 elementów. Następnie tworzone są dwa wątki; wątek Nadawca
i wątek Odbiorca
, po czym oba wątki rozpoczynają swoją pracę. Oba z nich używają – oczywiście – tej samej kolekcji.
Po uruchomieniu widzimy na konsoli kolejno pobierane i drukowane komunikaty.
Drukuję , KAROL MAY WINNETOU TOM I ROZDZIAŁ I GREENHORN Czy wiesz, ... mylę... KONIEC TOMU PIERWSZEGO Koniec drukowania