diff --git a/docs/book/Appendix-Collection-Topics.md b/docs/book/Appendix-Collection-Topics.md index 975484a..15dc2b0 100644 --- a/docs/book/Appendix-Collection-Topics.md +++ b/docs/book/Appendix-Collection-Topics.md @@ -2040,6 +2040,199 @@ two ## 队列 +有许多 **Queue** 实现,其中大多数是为并发应用程序设计的。许多实现都是通过排序行为而不是性能来区分的。这是一个涉及大多数 **Queue** 实现的基本示例,包括基于并发的队列。队列将元素从一端放入并从另一端取出: + +```java +// collectiontopics/QueueBehavior.java +// Compares basic behavior +import java.util.*; +import java.util.stream.*; +import java.util.concurrent.*; + +public class QueueBehavior { + static Stream strings() { + return Arrays.stream( + ("one two three four five six seven " + + "eight nine ten").split(" ")); + } + static void test(int id, Queue queue) { + System.out.print(id + ": "); + strings().map(queue::offer).count(); + while(queue.peek() != null) + System.out.print(queue.remove() + " "); + System.out.println(); + } + public static void main(String[] args) { + int count = 10; + test(1, new LinkedList<>()); + test(2, new PriorityQueue<>()); + test(3, new ArrayBlockingQueue<>(count)); + test(4, new ConcurrentLinkedQueue<>()); + test(5, new LinkedBlockingQueue<>()); + test(6, new PriorityBlockingQueue<>()); + test(7, new ArrayDeque<>()); + test(8, new ConcurrentLinkedDeque<>()); + test(9, new LinkedBlockingDeque<>()); + test(10, new LinkedTransferQueue<>()); + test(11, new SynchronousQueue<>()); + } +} +/* Output: +1: one two three four five six seven eight nine ten +2: eight five four nine one seven six ten three two +3: one two three four five six seven eight nine ten +4: one two three four five six seven eight nine ten +5: one two three four five six seven eight nine ten +6: eight five four nine one seven six ten three two +7: one two three four five six seven eight nine ten +8: one two three four five six seven eight nine ten +9: one two three four five six seven eight nine ten +10: one two three four five six seven eight nine ten +11: +*/ +``` + +**Deque** 接口也继承自 **Queue** 。 除优先级队列外,**Queue** 按照元素的插入顺序生成元素。 在此示例中,**SynchronousQueue** 不会产生任何结果,因为它是一个阻塞队列,其中每个插入操作必须等待另一个线程执行相应的删除操作,反之亦然。 + + +### 优先级队列 + +考虑一个待办事项列表,其中每个对象包含一个 **String** 以及主要和次要优先级值。通过实现 **Comparable** 接口来控制此待办事项列表的顺序: + +```java +// collectiontopics/ToDoList.java +// A more complex use of PriorityQueue +import java.util.*; + +class ToDoItem implements Comparable { + private char primary; + private int secondary; + private String item; + ToDoItem(String td, char pri, int sec) { + primary = pri; + secondary = sec; + item = td; + } + @Override + public int compareTo(ToDoItem arg) { + if(primary > arg.primary) + return +1; + if(primary == arg.primary) + if(secondary > arg.secondary) + return +1; + else if(secondary == arg.secondary) + return 0; + return -1; + } + @Override + public String toString() { + return Character.toString(primary) + + secondary + ": " + item; + } +} + +class ToDoList { + public static void main(String[] args) { + PriorityQueue toDo = + new PriorityQueue<>(); + toDo.add(new ToDoItem("Empty trash", 'C', 4)); + toDo.add(new ToDoItem("Feed dog", 'A', 2)); + toDo.add(new ToDoItem("Feed bird", 'B', 7)); + toDo.add(new ToDoItem("Mow lawn", 'C', 3)); + toDo.add(new ToDoItem("Water lawn", 'A', 1)); + toDo.add(new ToDoItem("Feed cat", 'B', 1)); + while(!toDo.isEmpty()) + System.out.println(toDo.remove()); + } +} +/* Output: +A1: Water lawn +A2: Feed dog +B1: Feed cat +B7: Feed bird +C3: Mow lawn +C4: Empty trash +*/ +``` + +这展示了通过优先级队列自动排序待办事项。 + + +### 双端队列 + +**Deque** (双端队列)就像一个队列,但是可以从任一端添加和删除元素。 Java 6为 **Deque** 添加了一个显式接口。以下是对实现了 **Deque** 的类的最基本的 **Deque** 方法的测试: + +```java +// collectiontopics/SimpleDeques.java +// Very basic test of Deques +import java.util.*; +import java.util.concurrent.*; +import java.util.function.*; + +class CountString implements Supplier { + private int n = 0; + CountString() {} + CountString(int start) { n = start; } + @Override + public String get() { + return Integer.toString(n++); + } +} + +public class SimpleDeques { + static void test(Deque deque) { + CountString s1 = new CountString(), + s2 = new CountString(20); + for(int n = 0; n < 8; n++) { + deque.offerFirst(s1.get()); + deque.offerLast(s2.get()); // Same as offer() + } + System.out.println(deque); + String result = ""; + while(deque.size() > 0) { + System.out.print(deque.peekFirst() + " "); + result += deque.pollFirst() + " "; + System.out.print(deque.peekLast() + " "); + result += deque.pollLast() + " "; + } + System.out.println("\n" + result); + } + public static void main(String[] args) { + int count = 10; + System.out.println("LinkedList"); + test(new LinkedList<>()); + System.out.println("ArrayDeque"); + test(new ArrayDeque<>()); + System.out.println("LinkedBlockingDeque"); + test(new LinkedBlockingDeque<>(count)); + System.out.println("ConcurrentLinkedDeque"); + test(new ConcurrentLinkedDeque<>()); + } +} +/* Output: +LinkedList +[7, 6, 5, 4, 3, 2, 1, 0, 20, 21, 22, 23, 24, 25, 26, +27] +7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20 +7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20 +ArrayDeque +[7, 6, 5, 4, 3, 2, 1, 0, 20, 21, 22, 23, 24, 25, 26, +27] +7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20 +7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20 +LinkedBlockingDeque +[4, 3, 2, 1, 0, 20, 21, 22, 23, 24] +4 24 3 23 2 22 1 21 0 20 +4 24 3 23 2 22 1 21 0 20 +ConcurrentLinkedDeque +[7, 6, 5, 4, 3, 2, 1, 0, 20, 21, 22, 23, 24, 25, 26, +27] +7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20 +7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20 +*/ +``` + +我只使用了 **Deque** 方法的“offer”和“poll”版本,因为当 **LinkedBlockingDeque** 的大小有限时,这些方法不会抛出异常。请注意, **LinkedBlockingDeque** 仅填充到它的限制大小为止,然后忽略额外的添加。 ## 理解Map