├── .gitignore ├── .idea ├── compiler.xml ├── libraries │ ├── Maven__junit_junit_4_12.xml │ └── Maven__org_hamcrest_hamcrest_core_1_3.xml ├── misc.xml ├── modules.xml ├── uiDesigner.xml └── vcs.xml ├── README.md ├── ThinkingInJavaNote.iml ├── pom.xml └── src ├── main └── java │ ├── ch14typeinfo │ └── DynamicProxyDemo.java │ ├── ch15generic │ ├── IterableFibonacci.java │ └── LinkedStack.java │ ├── ch16array │ ├── ArrayDefaultInitializer.java │ └── ArrayEquals.java │ ├── ch17containers │ ├── CountedString.java │ ├── Ex1.java │ ├── Ex11.java │ ├── Ex7.java │ ├── Ex8.java │ ├── Groundhog.java │ ├── Groundhog2.java │ ├── ListPerformance.java │ ├── MapPerformance.java │ ├── Prediction.java │ ├── SetPerformance.java │ ├── SimpleHashMap.java │ ├── SimpleHashMap20.java │ ├── SimpleHashMap22.java │ ├── SlowMap.java │ ├── SlowMap17.java │ ├── SpringDetector.java │ ├── SpringDetector2.java │ ├── Test.java │ ├── TestParam.java │ └── Tester.java │ ├── ch21concurrency │ ├── AtomicEvenGenerator.java │ ├── AtomicIntegerTest.java │ ├── AtomicityTest.java │ ├── AttempLocking.java │ ├── CachedThreadPool.java │ ├── CallableDemo.java │ ├── CaptureUncaughtException.java │ ├── CountDownLatchDemo.java │ ├── CriticalSection.java │ ├── DaemonFromFactory.java │ ├── Daemons.java │ ├── DaemonsDontRunFinally.java │ ├── DeadlockingDiningPhilosophers.java │ ├── DualSync.java │ ├── EvenChecker.java │ ├── EvenGenerator.java │ ├── Ex14Timer.java │ ├── Ex15SyncTest.java │ ├── Ex16LockTest.java │ ├── Ex18Interruption.java │ ├── Ex1Runner.java │ ├── Ex21WaitAndNotify.java │ ├── Ex22BusyWaitAndBetterWait.java │ ├── Ex27Restaurant.java │ ├── Ex30PipeIOUsingBlockingQueue.java │ ├── Ex5FibonacciCallable.java │ ├── Ex6RandomSleep.java │ ├── ExceptionThread.java │ ├── FixedDiningPhilosophers.java │ ├── FixedThreadPool.java │ ├── HorseRace.java │ ├── IntGenerator.java │ ├── Interrupting.java │ ├── Joining.java │ ├── LiftOff.java │ ├── MoreBasicThreads.java │ ├── MutexEvenGenerator.java │ ├── NIOInterruption.java │ ├── NaiveExceptionHandling.java │ ├── NotifyVsNotifyAll.java │ ├── OrnamentalGarden.java │ ├── PriorityBlockingQueueDemo.java │ ├── ResponsiveUI.java │ ├── Restaurant.java │ ├── SerialNumberChecker.java │ ├── SerialNumberGenerator.java │ ├── SettingDefaultHandler.java │ ├── SimpleDaemons.java │ ├── SingleThreadPool.java │ ├── SynchronizedEvenGenerator.java │ ├── TestCyclicBarrier.java │ ├── TestingBlockingQueues.java │ ├── ThreadVariations.java │ ├── ToastOMatic.java │ └── WaxOMatic.java │ ├── main_for_test │ └── MainForTest.java │ └── util │ ├── CollectionData.java │ ├── CountingGenerator.java │ ├── CountingIntegerList.java │ ├── CountingMapData.java │ ├── Countries.java │ ├── DaemonThreadFactory.java │ ├── Generated.java │ ├── Generator.java │ ├── MapEntry.java │ ├── Maps.java │ ├── Print.java │ ├── RandomGenerator.java │ └── TextFile.java └── test └── java └── ch15generic └── LinkedStackTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | .idea/workspace.xml 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__junit_junit_4_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Thinking in Java Notes 2 | 敲一些课后习题和sample code 3 | -------------------------------------------------------------------------------- /ThinkingInJavaNote.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | wenzheGroup 8 | ThinkingInJavaNote 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | org.apache.maven.plugins 14 | maven-compiler-plugin 15 | 16 | 1.8 17 | 1.8 18 | 19 | 20 | 21 | 22 | 23 | 24 | junit 25 | junit 26 | RELEASE 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/ch14typeinfo/DynamicProxyDemo.java: -------------------------------------------------------------------------------- 1 | package ch14typeinfo; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Proxy; 6 | 7 | public class DynamicProxyDemo { 8 | public static void main(String[] args) { 9 | Subject realSubject = new RealSubject(); 10 | ProxyHandler proxyHandler = new ProxyHandler(realSubject); 11 | 12 | // Class clazz = Proxy.getProxyClass( 13 | // RealSubject.class.getClassLoader(), 14 | // RealSubject.class.getInterfaces()); 15 | // System.out.println("Clazz " + clazz); 16 | // System.out.println("Clazz methods " + clazz.getMethods()); 17 | // System.out.println("Clazz super class " + clazz.getSuperclass()); 18 | 19 | Subject proxyObject = (Subject)Proxy.newProxyInstance( 20 | RealSubject.class.getClassLoader(), 21 | RealSubject.class.getInterfaces(), 22 | proxyHandler); 23 | proxyObject.request(); 24 | 25 | proxyObject.anotherRequest(); 26 | } 27 | } 28 | 29 | /** 30 | * 接口 31 | */ 32 | interface Subject{ 33 | String request(); 34 | void anotherRequest(); 35 | } 36 | 37 | /** 38 | * 委托类 39 | */ 40 | class RealSubject implements Subject{ 41 | @Override 42 | public String request(){ 43 | System.out.println("====RealSubject request===="); 44 | return "RealSubject.request()"; 45 | } 46 | 47 | @Override 48 | public void anotherRequest() { 49 | System.out.println("====RealSubject anotherRequest===="); 50 | } 51 | } 52 | 53 | /** 54 | * 代理类的调用处理器 55 | */ 56 | class ProxyHandler implements InvocationHandler { 57 | 58 | private Subject subject; 59 | public ProxyHandler(Subject subject) { 60 | this.subject = subject; 61 | } 62 | 63 | @Override 64 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 65 | System.out.println("Before " + method); 66 | Object result = method.invoke(subject, args); 67 | System.out.println("After " + method + ", Result " + result); 68 | return result; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/ch15generic/IterableFibonacci.java: -------------------------------------------------------------------------------- 1 | package ch15generic; 2 | 3 | import java.util.Iterator; 4 | 5 | public class IterableFibonacci implements Iterable{ 6 | int size; 7 | int[] cache; 8 | int position = 0; 9 | 10 | public IterableFibonacci(int size) { 11 | if (size <= 0) throw new IllegalArgumentException(); 12 | 13 | this.size = size; 14 | cache = new int[size]; 15 | 16 | cache[0] = 1; 17 | if (size > 1) 18 | cache[1] = 1; 19 | } 20 | 21 | private class FibonacciIterable implements Iterator { 22 | 23 | @Override 24 | public boolean hasNext() { 25 | return position < size; 26 | } 27 | 28 | @Override 29 | public Integer next() { 30 | if (position < 2) 31 | return cache[position++]; 32 | 33 | int result = cache[position - 2] + cache[position - 1]; 34 | cache[position++] = result; 35 | 36 | return result; 37 | } 38 | } 39 | @Override 40 | public Iterator iterator() { 41 | return new FibonacciIterable(); 42 | } 43 | } 44 | 45 | class IterableFibonacciTester { 46 | public static void main(String[] args) { 47 | for (int i: new IterableFibonacci(5)) { 48 | System.out.print(i+", "); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/ch15generic/LinkedStack.java: -------------------------------------------------------------------------------- 1 | package ch15generic; 2 | 3 | /** 4 | * Created by DengWenzhe on 3/5/17. 5 | */ 6 | public class LinkedStack { 7 | // Inner helper class 8 | private class Node { 9 | T item; 10 | Node next; 11 | 12 | Node() { } 13 | 14 | Node(T item, Node next) { 15 | this.item = item; 16 | this.next = next; 17 | } 18 | 19 | // boolean isEnd() { 20 | // return item == null && next == null; 21 | // } 22 | 23 | @Override 24 | public String toString() { 25 | return "Node " + item; 26 | } 27 | 28 | } 29 | 30 | Node top = null; 31 | int size = 0; 32 | 33 | public void push(T item) { 34 | Node newNode = new Node(item, top); 35 | top = newNode; 36 | size++; 37 | } 38 | 39 | public T pop() { 40 | if (isEmpty()) 41 | return null; 42 | 43 | T result = top.item; 44 | top = top.next; 45 | 46 | size--; 47 | return result; 48 | } 49 | 50 | public boolean isEmpty() { 51 | return top == null; 52 | } 53 | 54 | public int size() { 55 | return size; 56 | } 57 | } 58 | 59 | class LinkedStackTester { 60 | public static void main(String[] args) { 61 | String[] arr = "a b c d e f gg".split(" "); 62 | LinkedStack stack = new LinkedStack<>(); 63 | for (String s: arr) { 64 | stack.push(s); 65 | } 66 | 67 | while (!stack.isEmpty()) { 68 | System.out.println(stack.pop()); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/ch16array/ArrayDefaultInitializer.java: -------------------------------------------------------------------------------- 1 | package ch16array; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by DengWenzhe on 3/9/17. 7 | */ 8 | public class ArrayDefaultInitializer { 9 | 10 | public static void main(String[] args) { 11 | int[] a = new int[3]; 12 | System.out.println("a " + Arrays.toString(a)); 13 | 14 | //int[] b = new int[]; compile error 15 | //System.out.println(Arrays.toString(b)); 16 | 17 | int[][] b = new int[3][4]; 18 | System.out.println("b " + Arrays.deepToString(b)); 19 | 20 | int[][] c = new int[3][]; 21 | System.out.println("c " + Arrays.deepToString(c)); 22 | 23 | int[][][] d = new int[3][4][5]; 24 | System.out.println("d " + Arrays.deepToString(d)); 25 | 26 | int[][][] e = new int[3][4][]; 27 | System.out.println("e " + Arrays.deepToString(e)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/ch16array/ArrayEquals.java: -------------------------------------------------------------------------------- 1 | package ch16array; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by DengWenzhe on 3/9/17. 7 | */ 8 | public class ArrayEquals { 9 | int val; 10 | 11 | public ArrayEquals(int val) { 12 | this.val = val; 13 | } 14 | } 15 | 16 | class ArrayEqualsOverride { 17 | int val; 18 | 19 | public ArrayEqualsOverride(int val) { 20 | this.val = val; 21 | } 22 | 23 | @Override 24 | public boolean equals(Object another) { 25 | if (another == null) 26 | return false; 27 | 28 | ArrayEqualsOverride other; 29 | if (another instanceof ArrayEqualsOverride) 30 | other = (ArrayEqualsOverride) another; 31 | else 32 | return false; 33 | 34 | return other.val == this.val; 35 | } 36 | } 37 | 38 | class ArrayEqualsTester { 39 | 40 | public static void main(String[] args) { 41 | ArrayEquals[] a = new ArrayEquals[] { 42 | new ArrayEquals(1), 43 | new ArrayEquals(2), 44 | new ArrayEquals(3) 45 | }; 46 | 47 | ArrayEquals[] b = new ArrayEquals[] { 48 | new ArrayEquals(1), 49 | new ArrayEquals(2), 50 | new ArrayEquals(3) 51 | }; 52 | 53 | System.out.println("a equals b " + Arrays.equals(a, b)); 54 | 55 | ArrayEqualsOverride[] c = new ArrayEqualsOverride[] { 56 | new ArrayEqualsOverride(1), 57 | new ArrayEqualsOverride(2), 58 | new ArrayEqualsOverride(3) 59 | }; 60 | 61 | ArrayEqualsOverride[] d = new ArrayEqualsOverride[] { 62 | new ArrayEqualsOverride(1), 63 | new ArrayEqualsOverride(2), 64 | new ArrayEqualsOverride(3) 65 | }; 66 | 67 | System.out.println("c equals d " + Arrays.equals(c, d)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/CountedString.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | import static util.Print.*; 5 | 6 | public class CountedString { 7 | private static List created = 8 | new ArrayList(); 9 | private String s; 10 | private int id = 0; 11 | public CountedString(String str) { 12 | s = str; 13 | created.add(s); 14 | // id is the total number of instances 15 | // of this string in use by CountedString: 16 | for(String s2 : created) 17 | if(s2.equals(s)) 18 | id++; 19 | } 20 | public String toString() { 21 | return "String: " + s + " id: " + id + 22 | " hashCode(): " + hashCode(); 23 | } 24 | public int hashCode() { 25 | // The very simple approach: 26 | // return s.hashCode() * id; 27 | // Using Joshua Bloch's recipe: 28 | int result = 17; 29 | result = 37 * result + s.hashCode(); 30 | result = 37 * result + id; 31 | return result; 32 | } 33 | public boolean equals(Object o) { 34 | return o instanceof CountedString && 35 | s.equals(((CountedString)o).s) && 36 | id == ((CountedString)o).id; 37 | } 38 | public static void main(String[] args) { 39 | Map map = 40 | new HashMap(); 41 | CountedString[] cs = new CountedString[5]; 42 | for(int i = 0; i < cs.length; i++) { 43 | cs[i] = new CountedString("hi"); 44 | map.put(cs[i], i); // Autobox int -> Integer 45 | } 46 | print(map); 47 | for(CountedString cstring : cs) { 48 | print("Looking up " + cstring); 49 | print(map.get(cstring)); 50 | } 51 | } 52 | } /* Output: (Sample) 53 | {String: hi id: 4 hashCode(): 146450=3, String: hi id: 1 hashCode(): 146447=0, String: hi id: 3 hashCode(): 146449=2, String: hi id: 5 hashCode(): 146451=4, String: hi id: 2 hashCode(): 146448=1} 54 | Looking up String: hi id: 1 hashCode(): 146447 55 | 0 56 | Looking up String: hi id: 2 hashCode(): 146448 57 | 1 58 | Looking up String: hi id: 3 hashCode(): 146449 59 | 2 60 | Looking up String: hi id: 4 hashCode(): 146450 61 | 3 62 | Looking up String: hi id: 5 hashCode(): 146451 63 | 4 64 | */ 65 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/Ex1.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | import static util.Countries.DATA; 5 | 6 | /** 7 | * Created by DengWenzhe on 3/19/17. 8 | */ 9 | public class Ex1 { 10 | public static void main(String[] args) { 11 | List arrayList = new ArrayList<>(); 12 | List linkedList = new LinkedList<>(); 13 | 14 | for (String[] country: DATA) { 15 | arrayList.add(country[0]); 16 | linkedList.add(country[1]); 17 | } 18 | Collections.sort(arrayList); 19 | Collections.sort(linkedList); 20 | 21 | System.out.print("Countries: "); 22 | System.out.println(arrayList); 23 | System.out.print("Capitals: "); 24 | System.out.println(linkedList); 25 | 26 | for (int i = 0 ; i < 3; i++) { 27 | Collections.shuffle(arrayList); 28 | Collections.shuffle(linkedList); 29 | 30 | System.out.print("Countries: "); 31 | System.out.println(arrayList); 32 | System.out.print("Capitals: "); 33 | System.out.println(linkedList); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/Ex11.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.Comparator; 4 | import java.util.PriorityQueue; 5 | import java.util.Queue; 6 | import java.util.concurrent.ThreadLocalRandom; 7 | 8 | /** 9 | * Created by DengWenzhe on 3/19/17. 10 | */ 11 | public class Ex11 { 12 | public static void main(String[] args) { 13 | Queue heap = new PriorityQueue<>(); 14 | for (int i = 0; i < 10; i++) { 15 | heap.offer(new Item()); 16 | } 17 | 18 | while (!heap.isEmpty()) { 19 | System.out.print(heap.poll().val + ", "); 20 | } 21 | } 22 | } 23 | 24 | class Item implements Comparable { 25 | int val = ThreadLocalRandom.current().nextInt(100); 26 | 27 | @Override 28 | public int compareTo(Item o) { 29 | return Integer.compare(val, o.val); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/Ex7.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | import util.Countries; 5 | 6 | /** 7 | * Created by DengWenzhe on 3/19/17. 8 | */ 9 | public class Ex7 { 10 | public static void main(String[] args) { 11 | List arrayList = new ArrayList<>(Countries.names(10)); 12 | List linkedList = new LinkedList<>(Countries.names(10)); 13 | 14 | System.out.println("arrayList " + arrayList); 15 | System.out.println("linkedList " + linkedList); 16 | 17 | ListIterator li1 = arrayList.listIterator(arrayList.size()); 18 | ListIterator li2 = linkedList.listIterator(); 19 | 20 | int step = 0; 21 | while (li1.hasPrevious() && li2.hasNext()) { 22 | String str1 = li1.previous(); 23 | String str2 = li2.next(); 24 | 25 | if (step % 2 == 1) { 26 | li1.add(str2); 27 | } 28 | step++; 29 | } 30 | 31 | System.out.println("arrayList " + arrayList); 32 | System.out.println("linkedList " + linkedList); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/Ex8.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | /** 4 | * Created by DengWenzhe on 3/19/17. 5 | */ 6 | public class Ex8 { 7 | public static void main(String[] args) { 8 | Node node1 = new Node("node1"); 9 | Node node2 = new Node("node2"); 10 | Node node3 = new Node("node3"); 11 | 12 | SList sList = new SList<>(); 13 | SListIterator iter = sList.listIterator(); 14 | iter.insert("1"); 15 | iter.insert("2"); 16 | iter.insert("3"); 17 | iter.insert("4"); 18 | 19 | System.out.println(sList); 20 | 21 | iter = sList.listIterator(); 22 | iter.remove(); 23 | System.out.println(sList); 24 | 25 | iter.remove(); 26 | System.out.println(sList); 27 | } 28 | } 29 | class SList { 30 | Node dummyHead = new Node(null); 31 | 32 | SListIterator listIterator() { 33 | return new SListIterator(dummyHead); 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | StringBuffer sb = new StringBuffer(); 39 | SListIterator iter = listIterator(); 40 | while (iter.hasNext()) { 41 | sb.append("Node "); 42 | sb.append(iter.next()); 43 | sb.append(", "); 44 | } 45 | 46 | return sb.toString(); 47 | } 48 | } 49 | 50 | class SListIterator { 51 | Node current = null; 52 | public SListIterator(Node node) { 53 | current = node; 54 | } 55 | 56 | public boolean hasNext() { 57 | return current.next != null; 58 | } 59 | 60 | public E next() { 61 | current = current.next; 62 | return current.val; 63 | } 64 | 65 | public void insert(E element) { 66 | current.next = new Node(element, current.next); 67 | current = current.next; 68 | } 69 | 70 | public void remove() { 71 | if (current.next != null) 72 | current.next = current.next.next; 73 | } 74 | } 75 | 76 | class Node { 77 | E val; 78 | Node next; 79 | 80 | public Node(E val) { 81 | this.val = val; 82 | } 83 | 84 | public Node(E val, Node next) { 85 | this.val = val; 86 | this.next = next; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/Groundhog.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | /** 4 | * Created by DengWenzhe on 3/22/17. 5 | */ 6 | public class Groundhog { 7 | protected int number; 8 | public Groundhog(int n) { number = n; } 9 | public String toString() { 10 | return "Groundhog #" + number; 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/java/ch17containers/Groundhog2.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | public class Groundhog2 extends Groundhog{ 4 | 5 | public Groundhog2(int n) { 6 | super(n); 7 | } 8 | 9 | @Override 10 | public int hashCode() { 11 | return number; 12 | } 13 | 14 | @Override 15 | public boolean equals(Object o) { 16 | return o instanceof Groundhog2 && 17 | ((Groundhog2) o).number == this.number; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/ListPerformance.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | import util.*; 5 | 6 | public class ListPerformance { 7 | static Random rand = new Random(); 8 | static int reps = 1000; 9 | static List>> tests = 10 | new ArrayList>>(); 11 | static List>> qTests = 12 | new ArrayList>>(); 13 | static { 14 | tests.add(new Test>("add") { 15 | int test(List list, TestParam tp) { 16 | int loops = tp.loops; 17 | int listSize = tp.size; 18 | for(int i = 0; i < loops; i++) { 19 | list.clear(); 20 | for(int j = 0; j < listSize; j++) 21 | list.add(j); 22 | } 23 | return loops * listSize; 24 | } 25 | }); 26 | tests.add(new Test>("get") { 27 | int test(List list, TestParam tp) { 28 | int loops = tp.loops * reps; 29 | int listSize = list.size(); 30 | for(int i = 0; i < loops; i++) 31 | list.get(rand.nextInt(listSize)); 32 | return loops; 33 | } 34 | }); 35 | tests.add(new Test>("set") { 36 | int test(List list, TestParam tp) { 37 | int loops = tp.loops * reps; 38 | int listSize = list.size(); 39 | for(int i = 0; i < loops; i++) 40 | list.set(rand.nextInt(listSize), 47); 41 | return loops; 42 | } 43 | }); 44 | tests.add(new Test>("iteradd") { 45 | int test(List list, TestParam tp) { 46 | final int LOOPS = 1000000; 47 | int half = list.size() / 2; 48 | ListIterator it = list.listIterator(half); 49 | for(int i = 0; i < LOOPS; i++) 50 | it.add(47); 51 | return LOOPS; 52 | } 53 | }); 54 | tests.add(new Test>("insert") { 55 | int test(List list, TestParam tp) { 56 | int loops = tp.loops; 57 | for(int i = 0; i < loops; i++) 58 | list.add(5, 47); // Minimize random-access cost 59 | return loops; 60 | } 61 | }); 62 | tests.add(new Test>("remove") { 63 | int test(List list, TestParam tp) { 64 | int loops = tp.loops; 65 | int size = tp.size; 66 | for(int i = 0; i < loops; i++) { 67 | list.clear(); 68 | list.addAll(new CountingIntegerList(size)); 69 | while(list.size() > 5) 70 | list.remove(5); // Minimize random-access cost 71 | } 72 | return loops * size; 73 | } 74 | }); 75 | // Tests for queue behavior: 76 | qTests.add(new Test>("addFirst") { 77 | int test(LinkedList list, TestParam tp) { 78 | int loops = tp.loops; 79 | int size = tp.size; 80 | for(int i = 0; i < loops; i++) { 81 | list.clear(); 82 | for(int j = 0; j < size; j++) 83 | list.addFirst(47); 84 | } 85 | return loops * size; 86 | } 87 | }); 88 | qTests.add(new Test>("addLast") { 89 | int test(LinkedList list, TestParam tp) { 90 | int loops = tp.loops; 91 | int size = tp.size; 92 | for(int i = 0; i < loops; i++) { 93 | list.clear(); 94 | for(int j = 0; j < size; j++) 95 | list.addLast(47); 96 | } 97 | return loops * size; 98 | } 99 | }); 100 | qTests.add( 101 | new Test>("rmFirst") { 102 | int test(LinkedList list, TestParam tp) { 103 | int loops = tp.loops; 104 | int size = tp.size; 105 | for(int i = 0; i < loops; i++) { 106 | list.clear(); 107 | list.addAll(new CountingIntegerList(size)); 108 | while(list.size() > 0) 109 | list.removeFirst(); 110 | } 111 | return loops * size; 112 | } 113 | }); 114 | qTests.add(new Test>("rmLast") { 115 | int test(LinkedList list, TestParam tp) { 116 | int loops = tp.loops; 117 | int size = tp.size; 118 | for(int i = 0; i < loops; i++) { 119 | list.clear(); 120 | list.addAll(new CountingIntegerList(size)); 121 | while(list.size() > 0) 122 | list.removeLast(); 123 | } 124 | return loops * size; 125 | } 126 | }); 127 | } 128 | static class ListTester extends Tester> { 129 | public ListTester(List container, 130 | List>> tests) { 131 | super(container, tests); 132 | } 133 | // Fill to the appropriate size before each test: 134 | @Override protected List initialize(int size){ 135 | container.clear(); 136 | container.addAll(new CountingIntegerList(size)); 137 | return container; 138 | } 139 | // Convenience method: 140 | public static void run(List list, 141 | List>> tests) { 142 | new ListTester(list, tests).timedTest(); 143 | } 144 | } 145 | public static void main(String[] args) { 146 | if(args.length > 0) 147 | Tester.defaultParams = TestParam.array(args); 148 | // Can only do these two tests on an array: 149 | Tester> arrayTest = 150 | new Tester>(null, tests.subList(1, 3)){ 151 | // This will be called before each test. It 152 | // produces a non-resizeable array-backed list: 153 | @Override protected 154 | List initialize(int size) { 155 | Integer[] ia = Generated.array(Integer.class, 156 | new CountingGenerator.Integer(), size); 157 | return Arrays.asList(ia); 158 | } 159 | }; 160 | arrayTest.setHeadline("Array as List"); 161 | arrayTest.timedTest(); 162 | Tester.defaultParams= TestParam.array( 163 | 10, 5000, 100, 5000, 1000, 1000, 10000, 200); 164 | if(args.length > 0) 165 | Tester.defaultParams = TestParam.array(args); 166 | ListTester.run(new ArrayList(), tests); 167 | ListTester.run(new LinkedList(), tests); 168 | ListTester.run(new Vector(), tests); 169 | Tester.fieldWidth = 12; 170 | Tester> qTest = 171 | new Tester>( 172 | new LinkedList(), qTests); 173 | qTest.setHeadline("Queue tests"); 174 | qTest.timedTest(); 175 | } 176 | } /* Output: (Sample) 177 | --- Array as List --- 178 | size get set 179 | 10 130 183 180 | 100 130 164 181 | 1000 129 165 182 | 10000 129 165 183 | --------------------- ArrayList --------------------- 184 | size add get set iteradd insert remove 185 | 10 121 139 191 435 3952 446 186 | 100 72 141 191 247 3934 296 187 | 1000 98 141 194 839 2202 923 188 | 10000 122 144 190 6880 14042 7333 189 | --------------------- LinkedList --------------------- 190 | size add get set iteradd insert remove 191 | 10 182 164 198 658 366 262 192 | 100 106 202 230 457 108 201 193 | 1000 133 1289 1353 430 136 239 194 | 10000 172 13648 13187 435 255 239 195 | ----------------------- Vector ----------------------- 196 | size add get set iteradd insert remove 197 | 10 129 145 187 290 3635 253 198 | 100 72 144 190 263 3691 292 199 | 1000 99 145 193 846 2162 927 200 | 10000 108 145 186 6871 14730 7135 201 | -------------------- Queue tests -------------------- 202 | size addFirst addLast rmFirst rmLast 203 | 10 199 163 251 253 204 | 100 98 92 180 179 205 | 1000 99 93 216 212 206 | 10000 111 109 262 384 207 | */ -------------------------------------------------------------------------------- /src/main/java/ch17containers/MapPerformance.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | 5 | public class MapPerformance { 6 | static List>> tests = 7 | new ArrayList>>(); 8 | static { 9 | tests.add(new Test>("put") { 10 | int test(Map map, TestParam tp) { 11 | int loops = tp.loops; 12 | int size = tp.size; 13 | for(int i = 0; i < loops; i++) { 14 | map.clear(); 15 | for(int j = 0; j < size; j++) 16 | map.put(j, j); 17 | } 18 | return loops * size; 19 | } 20 | }); 21 | tests.add(new Test>("get") { 22 | int test(Map map, TestParam tp) { 23 | int loops = tp.loops; 24 | int span = tp.size * 2; 25 | for(int i = 0; i < loops; i++) 26 | for(int j = 0; j < span; j++) 27 | map.get(j); 28 | return loops * span; 29 | } 30 | }); 31 | tests.add(new Test>("iterate") { 32 | int test(Map map, TestParam tp) { 33 | int loops = tp.loops * 10; 34 | for(int i = 0; i < loops; i ++) { 35 | Iterator it = map.entrySet().iterator(); 36 | while(it.hasNext()) 37 | it.next(); 38 | } 39 | return loops * map.size(); 40 | } 41 | }); 42 | } 43 | public static void main(String[] args) { 44 | if(args.length > 0) 45 | Tester.defaultParams = TestParam.array(args); 46 | Tester.run(new TreeMap(), tests); 47 | Tester.run(new HashMap(), tests); 48 | Tester.run(new LinkedHashMap(),tests); 49 | Tester.run( 50 | new IdentityHashMap(), tests); 51 | Tester.run(new WeakHashMap(), tests); 52 | Tester.run(new Hashtable(), tests); 53 | } 54 | } /* Output: (Sample) 55 | ---------- TreeMap ---------- 56 | size put get iterate 57 | 10 748 168 100 58 | 100 506 264 76 59 | 1000 771 450 78 60 | 10000 2962 561 83 61 | ---------- HashMap ---------- 62 | size put get iterate 63 | 10 281 76 93 64 | 100 179 70 73 65 | 1000 267 102 72 66 | 10000 1305 265 97 67 | ------- LinkedHashMap ------- 68 | size put get iterate 69 | 10 354 100 72 70 | 100 273 89 50 71 | 1000 385 222 56 72 | 10000 2787 341 56 73 | ------ IdentityHashMap ------ 74 | size put get iterate 75 | 10 290 144 101 76 | 100 204 287 132 77 | 1000 508 336 77 78 | 10000 767 266 56 79 | -------- WeakHashMap -------- 80 | size put get iterate 81 | 10 484 146 151 82 | 100 292 126 117 83 | 1000 411 136 152 84 | 10000 2165 138 555 85 | --------- Hashtable --------- 86 | size put get iterate 87 | 10 264 113 113 88 | 100 181 105 76 89 | 1000 260 201 80 90 | 10000 1245 134 77 91 | */ 92 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/Prediction.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.concurrent.ThreadLocalRandom; 4 | 5 | public class Prediction { 6 | private static ThreadLocalRandom random = ThreadLocalRandom.current(); 7 | private boolean shadow = random.nextBoolean(); 8 | 9 | @Override 10 | public String toString() { 11 | if (shadow) 12 | return "Six more weeks of Winter!"; 13 | else 14 | return "Early Spring!"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/SetPerformance.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | 5 | public class SetPerformance { 6 | static List>> tests = 7 | new ArrayList>>(); 8 | static { 9 | tests.add(new Test>("add") { 10 | int test(Set set, TestParam tp) { 11 | int loops = tp.loops; 12 | int size = tp.size; 13 | for(int i = 0; i < loops; i++) { 14 | set.clear(); 15 | for(int j = 0; j < size; j++) 16 | set.add(j); 17 | } 18 | return loops * size; 19 | } 20 | }); 21 | tests.add(new Test>("contains") { 22 | int test(Set set, TestParam tp) { 23 | int loops = tp.loops; 24 | int span = tp.size * 2; 25 | for(int i = 0; i < loops; i++) 26 | for(int j = 0; j < span; j++) 27 | set.contains(j); 28 | return loops * span; 29 | } 30 | }); 31 | tests.add(new Test>("iterate") { 32 | int test(Set set, TestParam tp) { 33 | int loops = tp.loops * 10; 34 | for(int i = 0; i < loops; i++) { 35 | Iterator it = set.iterator(); 36 | while(it.hasNext()) 37 | it.next(); 38 | } 39 | return loops * set.size(); 40 | } 41 | }); 42 | } 43 | public static void main(String[] args) { 44 | if(args.length > 0) 45 | Tester.defaultParams = TestParam.array(args); 46 | Tester.fieldWidth = 10; 47 | Tester.run(new TreeSet(), tests); 48 | Tester.run(new HashSet(), tests); 49 | Tester.run(new LinkedHashSet(), tests); 50 | } 51 | } /* Output: (Sample) 52 | ------------- TreeSet ------------- 53 | size add contains iterate 54 | 10 746 173 89 55 | 100 501 264 68 56 | 1000 714 410 69 57 | 10000 1975 552 69 58 | ------------- HashSet ------------- 59 | size add contains iterate 60 | 10 308 91 94 61 | 100 178 75 73 62 | 1000 216 110 72 63 | 10000 711 215 100 64 | ---------- LinkedHashSet ---------- 65 | size add contains iterate 66 | 10 350 65 83 67 | 100 270 74 55 68 | 1000 303 111 54 69 | 10000 1615 256 58 70 | */ -------------------------------------------------------------------------------- /src/main/java/ch17containers/SimpleHashMap.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | import util.*; 5 | 6 | public class SimpleHashMap extends AbstractMap { 7 | // Choose a prime number for the hash table 8 | // size, to achieve a uniform distribution: 9 | static final int SIZE = 997; 10 | // You can't have a physical array of generics, 11 | // but you can upcast to one: 12 | @SuppressWarnings("unchecked") 13 | LinkedList>[] buckets = 14 | new LinkedList[SIZE]; 15 | public V put(K key, V value) { 16 | V oldValue = null; 17 | int index = Math.abs(key.hashCode()) % SIZE; 18 | if(buckets[index] == null) 19 | buckets[index] = new LinkedList>(); 20 | LinkedList> bucket = buckets[index]; 21 | MapEntry pair = new MapEntry(key, value); 22 | boolean found = false; 23 | ListIterator> it = bucket.listIterator(); 24 | while(it.hasNext()) { 25 | MapEntry iPair = it.next(); 26 | if(iPair.getKey().equals(key)) { 27 | oldValue = iPair.getValue(); 28 | it.set(pair); // Replace old with new 29 | found = true; 30 | break; 31 | } 32 | } 33 | if(!found) 34 | buckets[index].add(pair); 35 | return oldValue; 36 | } 37 | public V get(Object key) { 38 | int index = Math.abs(key.hashCode()) % SIZE; 39 | if(buckets[index] == null) return null; 40 | for(MapEntry iPair : buckets[index]) 41 | if(iPair.getKey().equals(key)) 42 | return iPair.getValue(); 43 | return null; 44 | } 45 | public Set> entrySet() { 46 | Set> set= new HashSet>(); 47 | for(LinkedList> bucket : buckets) { 48 | if(bucket == null) continue; 49 | for(MapEntry mpair : bucket) 50 | set.add(mpair); 51 | } 52 | return set; 53 | } 54 | public static void main(String[] args) { 55 | SimpleHashMap m = 56 | new SimpleHashMap(); 57 | m.putAll(Countries.capitals(25)); 58 | System.out.println(m); 59 | System.out.println(m.get("ERITREA")); 60 | System.out.println(m.entrySet()); 61 | } 62 | } /* Output: 63 | {CAMEROON=Yaounde, CONGO=Brazzaville, CHAD=N'djamena, COTE D'IVOIR (IVORY COAST)=Yamoussoukro, CENTRAL AFRICAN REPUBLIC=Bangui, GUINEA=Conakry, BOTSWANA=Gaberone, BISSAU=Bissau, EGYPT=Cairo, ANGOLA=Luanda, BURKINA FASO=Ouagadougou, ERITREA=Asmara, THE GAMBIA=Banjul, KENYA=Nairobi, GABON=Libreville, CAPE VERDE=Praia, ALGERIA=Algiers, COMOROS=Moroni, EQUATORIAL GUINEA=Malabo, BURUNDI=Bujumbura, BENIN=Porto-Novo, BULGARIA=Sofia, GHANA=Accra, DJIBOUTI=Dijibouti, ETHIOPIA=Addis Ababa} 64 | Asmara 65 | [CAMEROON=Yaounde, CONGO=Brazzaville, CHAD=N'djamena, COTE D'IVOIR (IVORY COAST)=Yamoussoukro, CENTRAL AFRICAN REPUBLIC=Bangui, GUINEA=Conakry, BOTSWANA=Gaberone, BISSAU=Bissau, EGYPT=Cairo, ANGOLA=Luanda, BURKINA FASO=Ouagadougou, ERITREA=Asmara, THE GAMBIA=Banjul, KENYA=Nairobi, GABON=Libreville, CAPE VERDE=Praia, ALGERIA=Algiers, COMOROS=Moroni, EQUATORIAL GUINEA=Malabo, BURUNDI=Bujumbura, BENIN=Porto-Novo, BULGARIA=Sofia, GHANA=Accra, DJIBOUTI=Dijibouti, ETHIOPIA=Addis Ababa] 66 | */ 67 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/SimpleHashMap20.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import util.MapEntry; 4 | 5 | import java.util.*; 6 | 7 | public class SimpleHashMap20 extends AbstractMap { 8 | // Choose a prime number for the hash table 9 | // size, to achieve a uniform distribution: 10 | static final int SIZE = 997; 11 | // You can't have a physical array of generics, 12 | // but you can upcast to one: 13 | @SuppressWarnings("unchecked") 14 | LinkedList>[] buckets = 15 | new LinkedList[SIZE]; 16 | public V put(K key, V value) { 17 | V oldValue = null; 18 | int index = Math.abs(key.hashCode()) % SIZE; 19 | if(buckets[index] == null) 20 | buckets[index] = new LinkedList>(); 21 | LinkedList> bucket = buckets[index]; 22 | MapEntry pair = new MapEntry(key, value); 23 | boolean found = false; 24 | ListIterator> it = bucket.listIterator(); 25 | while(it.hasNext()) { 26 | MapEntry iPair = it.next(); 27 | System.out.print("报告!发现冲突! " + iPair); 28 | if(iPair.getKey().equals(key)) { 29 | oldValue = iPair.getValue(); 30 | it.set(pair); // Replace old with new 31 | found = true; 32 | break; 33 | } 34 | } 35 | if(!found) 36 | buckets[index].add(pair); 37 | return oldValue; 38 | } 39 | public V get(Object key) { 40 | int index = Math.abs(key.hashCode()) % SIZE; 41 | if(buckets[index] == null) return null; 42 | for(MapEntry iPair : buckets[index]) 43 | if(iPair.getKey().equals(key)) 44 | return iPair.getValue(); 45 | return null; 46 | } 47 | public Set> entrySet() { 48 | Set> set= new HashSet>(); 49 | for(LinkedList> bucket : buckets) { 50 | if(bucket == null) continue; 51 | for(MapEntry mpair : bucket) 52 | set.add(mpair); 53 | } 54 | return set; 55 | } 56 | public static void main(String[] args) { 57 | SimpleHashMap20 map = 58 | new SimpleHashMap20(); 59 | map.put("Hello", "World"); 60 | map.put("Thinking", "In Java"); 61 | map.put("Hello", "My Friend"); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/SimpleHashMap22.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import util.MapEntry; 4 | import java.util.*; 5 | 6 | public class SimpleHashMap22 extends AbstractMap { 7 | // Choose a prime number for the hash table 8 | // size, to achieve a uniform distribution: 9 | static final int SIZE = 997; 10 | // You can't have a physical array of generics, 11 | // but you can upcast to one: 12 | @SuppressWarnings("unchecked") 13 | LinkedList>[] buckets = 14 | new LinkedList[SIZE]; 15 | public V put(K key, V value) { 16 | V oldValue = null; 17 | int index = Math.abs(key.hashCode()) % SIZE; 18 | if(buckets[index] == null) 19 | buckets[index] = new LinkedList>(); 20 | LinkedList> bucket = buckets[index]; 21 | MapEntry pair = new MapEntry(key, value); 22 | boolean found = false; 23 | ListIterator> it = bucket.listIterator(); 24 | while(it.hasNext()) { 25 | MapEntry iPair = it.next(); 26 | System.out.print("报告!发现冲突! " + iPair); 27 | if(iPair.getKey().equals(key)) { 28 | oldValue = iPair.getValue(); 29 | it.set(pair); // Replace old with new 30 | found = true; 31 | break; 32 | } 33 | } 34 | if(!found) 35 | buckets[index].add(pair); 36 | return oldValue; 37 | } 38 | public V get(Object key) { 39 | int index = Math.abs(key.hashCode()) % SIZE; 40 | if(buckets[index] == null) return null; 41 | for(MapEntry iPair : buckets[index]) 42 | if(iPair.getKey().equals(key)) 43 | return iPair.getValue(); 44 | return null; 45 | } 46 | public Set> entrySet() { 47 | Set> set= new HashSet>(); 48 | for(LinkedList> bucket : buckets) { 49 | if(bucket == null) continue; 50 | for(MapEntry mpair : bucket) 51 | set.add(mpair); 52 | } 53 | return set; 54 | } 55 | 56 | @Override 57 | public void clear() { 58 | Arrays.fill(buckets, null); 59 | } 60 | 61 | @Override 62 | public V remove(Object key) { 63 | int index = Math.abs(key.hashCode()) % SIZE; 64 | if (buckets[index] == null) 65 | return null; 66 | 67 | ListIterator> iter = buckets[index].listIterator(); 68 | while (iter.hasNext()) { 69 | MapEntry entry = iter.next(); 70 | if (entry.getKey().equals(key)) { 71 | iter.remove(); 72 | return entry.getValue(); 73 | } 74 | } 75 | 76 | return null; 77 | } 78 | 79 | public static void main(String[] args) { 80 | SimpleHashMap22 map = 81 | new SimpleHashMap22(); 82 | map.put("Hello", "World"); 83 | map.put("Thinking", "In Java"); 84 | map.put("I like ", "Java"); 85 | System.out.println("Map: " + map); 86 | 87 | map.remove("Thinking"); 88 | System.out.println("After remove Thinking: " + map); 89 | 90 | map.clear(); 91 | System.out.println("After clear: " + map); 92 | } 93 | } -------------------------------------------------------------------------------- /src/main/java/ch17containers/SlowMap.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | import util.*; 5 | 6 | public class SlowMap extends AbstractMap { 7 | private List keys = new ArrayList(); 8 | private List values = new ArrayList(); 9 | public V put(K key, V value) { 10 | V oldValue = get(key); // The old value or null 11 | if(!keys.contains(key)) { 12 | keys.add(key); 13 | values.add(value); 14 | } else 15 | values.set(keys.indexOf(key), value); 16 | return oldValue; 17 | } 18 | public V get(Object key) { // key is type Object, not K 19 | if(!keys.contains(key)) 20 | return null; 21 | return values.get(keys.indexOf(key)); 22 | } 23 | public Set> entrySet() { 24 | Set> set= new HashSet>(); 25 | Iterator ki = keys.iterator(); 26 | Iterator vi = values.iterator(); 27 | while(ki.hasNext()) 28 | set.add(new MapEntry(ki.next(), vi.next())); 29 | return set; 30 | } 31 | public static void main(String[] args) { 32 | SlowMap m= new SlowMap(); 33 | m.putAll(Countries.capitals(15)); 34 | System.out.println(m); 35 | System.out.println(m.get("BULGARIA")); 36 | System.out.println(m.entrySet()); 37 | 38 | // SlowMap sm = new SlowMap<>(); 39 | // Maps.test(sm); 40 | } 41 | } /* Output: 42 | {CAMEROON=Yaounde, CHAD=N'djamena, CONGO=Brazzaville, CAPE VERDE=Praia, ALGERIA=Algiers, COMOROS=Moroni, CENTRAL AFRICAN REPUBLIC=Bangui, BOTSWANA=Gaberone, BURUNDI=Bujumbura, BENIN=Porto-Novo, BULGARIA=Sofia, EGYPT=Cairo, ANGOLA=Luanda, BURKINA FASO=Ouagadougou, DJIBOUTI=Dijibouti} 43 | Sofia 44 | [CAMEROON=Yaounde, CHAD=N'djamena, CONGO=Brazzaville, CAPE VERDE=Praia, ALGERIA=Algiers, COMOROS=Moroni, CENTRAL AFRICAN REPUBLIC=Bangui, BOTSWANA=Gaberone, BURUNDI=Bujumbura, BENIN=Porto-Novo, BULGARIA=Sofia, EGYPT=Cairo, ANGOLA=Luanda, BURKINA FASO=Ouagadougou, DJIBOUTI=Dijibouti] 45 | */ -------------------------------------------------------------------------------- /src/main/java/ch17containers/SlowMap17.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | import util.*; 5 | import static util.Print.*; 6 | 7 | public class SlowMap17 implements Map { 8 | private List keys = new ArrayList(); 9 | private List values = new ArrayList(); 10 | private EntrySet entries = new EntrySet(); 11 | private Set keySet = new KeySet(); 12 | public Set> entrySet() { return entries; } 13 | public Set keySet() { return keySet; } 14 | public V put(K key, V value) { 15 | V oldValue = get(key); // The old value or null 16 | if(!keys.contains(key)) { 17 | keys.add(key); 18 | values.add(value); 19 | } else 20 | values.set(keys.indexOf(key), value); 21 | return oldValue; 22 | } 23 | public V get(Object key) { // key is type Object, not K 24 | if(!keys.contains(key)) 25 | return null; 26 | return values.get(keys.indexOf(key)); 27 | } 28 | private class EntrySet extends AbstractSet> { 29 | public int size() { return keys.size(); } 30 | public Iterator> iterator() { 31 | return new Iterator>() { 32 | private int index = -1; 33 | public boolean hasNext() { 34 | return index < keys.size() - 1; 35 | } 36 | @SuppressWarnings("unchecked") 37 | public Map.Entry next() { 38 | int i = ++index; 39 | return new MapEntry( 40 | keys.get(i), values.get(i)); 41 | } 42 | public void remove() { 43 | keys.remove(index); 44 | values.remove(index--); 45 | } 46 | }; 47 | } 48 | } 49 | public void clear() { 50 | keys.clear(); 51 | values.clear(); 52 | } 53 | public boolean containsKey(Object key) { 54 | return keys.contains(key); 55 | } 56 | public boolean containsValue(Object value) { 57 | return values.contains(value); 58 | } 59 | public boolean equals(Object o) { 60 | if(o instanceof SlowMap17) { 61 | if(this.entrySet().equals(((SlowMap17)o).entrySet())) 62 | return true; 63 | } 64 | return false; 65 | } 66 | public int hashCode() { 67 | return this.entrySet().hashCode(); 68 | } 69 | public boolean isEmpty() { 70 | return this.entrySet().isEmpty(); 71 | } 72 | private class KeySet extends AbstractSet { 73 | public int size() { return keys.size(); } 74 | public Iterator iterator() { 75 | return new Iterator() { 76 | private int index = -1; 77 | public boolean hasNext() { 78 | return index < keys.size() - 1; 79 | } 80 | public K next() { 81 | int i = ++index; 82 | return keys.get(index); 83 | } 84 | public void remove() { 85 | keys.remove(index--); 86 | } 87 | }; 88 | } 89 | 90 | } 91 | public void putAll(Map m) { 92 | for(Map.Entry me : m.entrySet()) 93 | this.put(me.getKey(), me.getValue()); 94 | } 95 | public V remove(Object key) { 96 | V v = this.get(key); 97 | int i = keys.indexOf(key); 98 | keys.remove(i); 99 | values.remove(i); 100 | return v; 101 | } 102 | public int size() { return keys.size(); } 103 | public Collection values() { 104 | return values; 105 | } 106 | public String toString() { 107 | return this.entrySet().toString(); 108 | } 109 | public static void main(String[] args) { 110 | SlowMap17 m = new SlowMap17(); 111 | m.putAll(Countries.capitals(15)); 112 | print("m: " + m); 113 | print("m.get(\"BURUNDI\"): " + m.get("BURUNDI")); 114 | print("m.entrySet(): " + m.entrySet()); 115 | print("m.keySet(): " + m.keySet()); 116 | print("m.values() = " + m.values()); 117 | print("Two different maps: "); 118 | SlowMap17 m2 = new SlowMap17(); 119 | print("m.equals(m2): " + m.equals(m2)); 120 | m2.putAll(Countries.capitals(15)); 121 | print("Maps with same entries: "); 122 | print("m.equals(m2): " + m.equals(m2)); 123 | m.clear(); 124 | print("After m.clear(), m.isEmpty(): " + 125 | m.isEmpty() + ", m = " + m); 126 | m2.keySet().clear(); 127 | print("After m2.keySet().clear(), m2.isEmpty(): " 128 | + m2.isEmpty() + ", m2 = " + m2); 129 | 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/SpringDetector.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | import java.lang.reflect.Constructor; 5 | 6 | public class SpringDetector { 7 | public static 8 | void detectSpring(Class type) throws Exception { 9 | Constructor constructor = type.getConstructor(int.class); 10 | Map map = new HashMap<>(); 11 | 12 | for (int i = 0; i < 10; i++) { 13 | map.put(constructor.newInstance(i), new Prediction()); 14 | } 15 | 16 | System.out.println("Map " + map); 17 | 18 | Groundhog gh = constructor.newInstance(3); 19 | System.out.println("Looking up prediction for " + gh); 20 | if (map.containsKey(gh)) 21 | System.out.println(map.get(gh)); 22 | else 23 | System.out.println("Key not found " + gh); 24 | } 25 | 26 | public static void main(String[] args) throws Exception { 27 | detectSpring(Groundhog.class); 28 | } 29 | } /* Output 30 | Map {Groundhog #0=Early Spring!, Groundhog #5=Early Spring!, Groundhog #6=Six more weeks of Winter!, Groundhog #1=Six more weeks of Winter!, Groundhog #3=Early Spring!, Groundhog #7=Six more weeks of Winter!, Groundhog #4=Six more weeks of Winter!, Groundhog #8=Six more weeks of Winter!, Groundhog #9=Six more weeks of Winter!, Groundhog #2=Six more weeks of Winter!} 31 | Looking up prediction for Groundhog #3 32 | Key not found Groundhog #3 33 | */ 34 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/SpringDetector2.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | public class SpringDetector2 { 4 | public static void main(String[] args) throws Exception { 5 | SpringDetector.detectSpring(Groundhog2.class); 6 | } 7 | }/* Output 8 | Map {Groundhog #0=Early Spring!, Groundhog #1=Early Spring!, Groundhog #2=Six more weeks of Winter!, Groundhog #3=Early Spring!, Groundhog #4=Six more weeks of Winter!, Groundhog #5=Early Spring!, Groundhog #6=Six more weeks of Winter!, Groundhog #7=Six more weeks of Winter!, Groundhog #8=Six more weeks of Winter!, Groundhog #9=Early Spring!} 9 | Looking up prediction for Groundhog #3 10 | Early Spring! 11 | */ -------------------------------------------------------------------------------- /src/main/java/ch17containers/Test.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | public abstract class Test { 4 | String name; 5 | public Test(String name) { this.name = name; } 6 | // Override this method for different tests. 7 | // Returns actual number of repetitions of test. 8 | abstract int test(C container, TestParam tp); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/ch17containers/TestParam.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | public class TestParam { 4 | public final int size; 5 | public final int loops; 6 | public TestParam(int size, int loops) { 7 | this.size = size; 8 | this.loops = loops; 9 | } 10 | // Create an array of TestParam from a varargs sequence: 11 | public static TestParam[] array(int... values) { 12 | int size = values.length/2; 13 | TestParam[] result = new TestParam[size]; 14 | int n = 0; 15 | for(int i = 0; i < size; i++) 16 | result[i] = new TestParam(values[n++], values[n++]); 17 | return result; 18 | } 19 | // Convert a String array to a TestParam array: 20 | public static TestParam[] array(String[] values) { 21 | int[] vals = new int[values.length]; 22 | for(int i = 0; i < vals.length; i++) 23 | vals[i] = Integer.decode(values[i]); 24 | return array(vals); 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/ch17containers/Tester.java: -------------------------------------------------------------------------------- 1 | package ch17containers; 2 | 3 | import java.util.*; 4 | 5 | public class Tester { 6 | public static int fieldWidth = 8; 7 | public static TestParam[] defaultParams= TestParam.array( 8 | 10, 5000, 100, 5000, 1000, 5000, 10000, 500); 9 | // Override this to modify pre-test initialization: 10 | protected C initialize(int size) { return container; } 11 | protected C container; 12 | private String headline = ""; 13 | private List> tests; 14 | private static String stringField() { 15 | return "%" + fieldWidth + "s"; 16 | } 17 | private static String numberField() { 18 | return "%" + fieldWidth + "d"; 19 | } 20 | private static int sizeWidth = 5; 21 | private static String sizeField = "%" + sizeWidth + "s"; 22 | private TestParam[] paramList = defaultParams; 23 | public Tester(C container, List> tests) { 24 | this.container = container; 25 | this.tests = tests; 26 | if(container != null) 27 | headline = container.getClass().getSimpleName(); 28 | } 29 | public Tester(C container, List> tests, 30 | TestParam[] paramList) { 31 | this(container, tests); 32 | this.paramList = paramList; 33 | } 34 | public void setHeadline(String newHeadline) { 35 | headline = newHeadline; 36 | } 37 | // Generic methods for convenience : 38 | public static void run(C cntnr, List> tests){ 39 | new Tester(cntnr, tests).timedTest(); 40 | } 41 | public static void run(C cntnr, 42 | List> tests, TestParam[] paramList) { 43 | new Tester(cntnr, tests, paramList).timedTest(); 44 | } 45 | private void displayHeader() { 46 | // Calculate width and pad with '-': 47 | int width = fieldWidth * tests.size() + sizeWidth; 48 | int dashLength = width - headline.length() - 1; 49 | StringBuilder head = new StringBuilder(width); 50 | for(int i = 0; i < dashLength/2; i++) 51 | head.append('-'); 52 | head.append(' '); 53 | head.append(headline); 54 | head.append(' '); 55 | for(int i = 0; i < dashLength/2; i++) 56 | head.append('-'); 57 | System.out.println(head); 58 | // Print column headers: 59 | System.out.format(sizeField, "size"); 60 | for(Test test : tests) 61 | System.out.format(stringField(), test.name); 62 | System.out.println(); 63 | } 64 | // Run the tests for this container: 65 | public void timedTest() { 66 | displayHeader(); 67 | for(TestParam param : paramList) { 68 | System.out.format(sizeField, param.size); 69 | for(Test test : tests) { 70 | C kontainer = initialize(param.size); 71 | long start = System.nanoTime(); 72 | // Call the overriden method: 73 | int reps = test.test(kontainer, param); 74 | long duration = System.nanoTime() - start; 75 | long timePerRep = duration / reps; // Nanoseconds 76 | System.out.format(numberField(), timePerRep); 77 | } 78 | System.out.println(); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/AtomicEvenGenerator.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | public class AtomicEvenGenerator extends IntGenerator { 6 | private AtomicInteger currentEvenValue = new AtomicInteger(0); 7 | @Override 8 | public int next() { 9 | return currentEvenValue.addAndGet(2); 10 | } 11 | 12 | public static void main(String[] args) { 13 | EvenChecker.test(new AtomicEvenGenerator(), 10); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/AtomicIntegerTest.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.Timer; 4 | import java.util.TimerTask; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | import static util.Print.print; 8 | 9 | public class AtomicIntegerTest implements Runnable{ 10 | private AtomicInteger ai = new AtomicInteger(0); 11 | 12 | public int getValue() { 13 | return ai.get(); 14 | } 15 | 16 | public void evenIncrement() { 17 | ai.addAndGet(2); 18 | } 19 | @Override 20 | public void run() { 21 | while (true) { 22 | evenIncrement(); 23 | } 24 | } 25 | 26 | public static void main(String[] args) { 27 | new Timer().schedule(new TimerTask() { 28 | @Override 29 | public void run() { 30 | print("Time out"); 31 | System.exit(0); 32 | } 33 | }, 5000); 34 | 35 | AtomicIntegerTest ait = new AtomicIntegerTest(); 36 | new Thread(ait).start(); 37 | 38 | while(true) { 39 | int val = ait.getValue(); 40 | if (val % 2 == 1) { 41 | print("Not even! " + val); 42 | System.exit(0); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/AtomicityTest.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | public class AtomicityTest implements Runnable{ 7 | private int i = 0; 8 | public int getValue() { 9 | return i; 10 | } 11 | 12 | private synchronized void increment() { 13 | ++i; 14 | ++i; 15 | } 16 | 17 | @Override 18 | public void run() { 19 | while(true) { 20 | increment(); 21 | } 22 | } 23 | 24 | public static void main(String[] args) throws InterruptedException { 25 | ExecutorService exec = Executors.newSingleThreadExecutor(); 26 | AtomicityTest at = new AtomicityTest(); 27 | exec.execute(at); 28 | 29 | //Thread.sleep(1); 30 | while(true) { 31 | int val = at.getValue(); 32 | System.out.println(val); 33 | if (val % 2 != 0) { 34 | System.out.println("Not even! " + val); 35 | System.exit(0); 36 | } 37 | } 38 | } 39 | }/* Output 40 | 0 41 | 2402 42 | 2864 43 | 3476 44 | 4804 45 | 5118 46 | 6264 47 | 8276 48 | 9798 49 | 11118 50 | 12338 51 | 14188 52 | 15574 53 | 16938 54 | 18432 55 | 20562 56 | 22504 57 | 24040 58 | 25552 59 | 26824 60 | 28048 61 | 29240 62 | 30444 63 | 31742 64 | 33008 65 | 34216 66 | 35610 67 | 37566 68 | 39504 69 | 41166 70 | 42914 71 | 44422 72 | 46678 73 | 48438 74 | 50104 75 | 51788 76 | 53852 77 | 56362 78 | 58310 79 | 59750 80 | 61290 81 | 62942 82 | 64684 83 | 67306 84 | 69464 85 | 71206 86 | 73144 87 | 74898 88 | 76653 89 | Not even! 76653 90 | */ -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/AttempLocking.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import java.util.concurrent.locks.Lock; 5 | import java.util.concurrent.locks.ReentrantLock; 6 | 7 | import static util.Print.print; 8 | 9 | public class AttempLocking { 10 | private Lock lock = new ReentrantLock(); 11 | 12 | public void untimed() { 13 | boolean acquired = lock.tryLock(); 14 | try { 15 | print("tryLock() " + acquired); 16 | } finally { 17 | if (acquired) { 18 | lock.unlock(); 19 | } 20 | } 21 | } 22 | 23 | public void timed() { 24 | boolean acquired = false; 25 | try { 26 | acquired = lock.tryLock(2, TimeUnit.SECONDS); 27 | } catch (InterruptedException e) { 28 | e.printStackTrace(); 29 | } 30 | 31 | try { 32 | print("tryLock(2, TimeUnit.SECONDS) " + acquired); 33 | } finally { 34 | if (acquired) 35 | lock.unlock(); 36 | } 37 | } 38 | 39 | public static void main(String[] args) throws InterruptedException { 40 | final AttempLocking al = new AttempLocking(); 41 | al.untimed(); 42 | al.timed(); 43 | 44 | new Thread() { 45 | { setDaemon(true);} // If this is commented out, the thread can be created via lambda way 46 | public void run() { 47 | al.lock.lock(); // 为什么此处可以获取private域lock?因为内部类可以访问private成员? 48 | print("acquired"); 49 | } 50 | }.start(); 51 | Thread.yield(); // Give the new thread a chance to run 52 | Thread.sleep(200); // yield doesn't really work, have to sleep to let new thread 53 | // has a chance to get lock 54 | al.untimed(); 55 | al.timed(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/CachedThreadPool.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | 7 | public class CachedThreadPool { 8 | public static void main(String[] args) { 9 | ExecutorService executor = Executors.newCachedThreadPool(); 10 | for (int i = 0; i < 5; i++) { 11 | executor.execute(new LiftOff()); 12 | } 13 | executor.shutdown(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/CallableDemo.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.*; 6 | 7 | class TaskWithResult implements Callable { 8 | private static int taskCount = 0; 9 | private final int taskId = taskCount++; 10 | 11 | @Override 12 | public String call() throws Exception { 13 | return "Result of task " + taskId; 14 | } 15 | } 16 | public class CallableDemo { 17 | public static void main(String[] args) { 18 | ExecutorService executor = Executors.newCachedThreadPool(); 19 | List> results = new ArrayList<>(); 20 | for (int i = 0; i < 5; i++) { 21 | results.add(executor.submit(new TaskWithResult())); 22 | } 23 | 24 | for (Future result: results) { 25 | try { 26 | System.out.println(result.get()); 27 | } catch (InterruptedException e) { 28 | e.printStackTrace(); 29 | } catch (ExecutionException e) { 30 | e.printStackTrace(); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/CaptureUncaughtException.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.ThreadFactory; 7 | 8 | import static util.Print.print; 9 | 10 | 11 | class ExceptionThread2 implements Runnable { 12 | @Override 13 | public void run() { 14 | Thread t = Thread.currentThread(); 15 | print("run() by " + t); 16 | print("eh = " + t.getUncaughtExceptionHandler()); 17 | throw new RuntimeException(); 18 | } 19 | } 20 | 21 | class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { 22 | 23 | @Override 24 | public void uncaughtException(Thread t, Throwable e) { 25 | print(" caught " + e); 26 | } 27 | } 28 | 29 | class HandlerThreadFactory implements ThreadFactory { 30 | //private MyUncaughtExceptionHandler eh = new MyUncaughtExceptionHandler(); 31 | @Override 32 | public Thread newThread(Runnable r) { 33 | print("Creating new thread"); 34 | Thread t = new Thread(r); 35 | print("Created " + t); 36 | t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); 37 | print(" setUncaughtExceptionHandler " + t.getUncaughtExceptionHandler() 38 | + " on " + t); 39 | return t; 40 | } 41 | } 42 | public class CaptureUncaughtException { 43 | public static void main(String[] args) { 44 | ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory()); 45 | exec.execute(new ExceptionThread2()); 46 | } 47 | }/* Output doesn't match with the output on the BOOK! Two threads were created 48 | Creating new thread 49 | Created Thread[Thread-0,5,main] 50 | setUncaughtExceptionHandler ch21concurrency.MyUncaughtExceptionHandler@66d3c617 on Thread[Thread-0,5,main] 51 | run() by Thread[Thread-0,5,main] 52 | eh = ch21concurrency.MyUncaughtExceptionHandler@66d3c617 53 | Creating new thread 54 | Created Thread[Thread-1,5,main] 55 | setUncaughtExceptionHandler ch21concurrency.MyUncaughtExceptionHandler@782b1823 on Thread[Thread-1,5,main] 56 | caught java.lang.RuntimeException 57 | */ 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/CountDownLatchDemo.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.*; 4 | import java.util.*; 5 | import static util.Print.print; 6 | 7 | // Performs some portion of a task: 8 | class TaskPortion implements Runnable { 9 | private static int counter = 0; 10 | private final int id = counter++; 11 | private static Random rand = new Random(47); 12 | private final CountDownLatch latch; 13 | TaskPortion(CountDownLatch latch) { 14 | this.latch = latch; 15 | } 16 | public void run() { 17 | try { 18 | doWork(); 19 | latch.countDown(); 20 | } catch(InterruptedException ex) { 21 | // Acceptable way to exit 22 | } 23 | } 24 | public void doWork() throws InterruptedException { 25 | TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000)); 26 | print(this + "completed"); 27 | } 28 | public String toString() { 29 | return String.format("%1$-3d ", id); 30 | } 31 | } 32 | 33 | // Waits on the CountDownLatch: 34 | class WaitingTask implements Runnable { 35 | private static int counter = 0; 36 | private final int id = counter++; 37 | private final CountDownLatch latch; 38 | WaitingTask(CountDownLatch latch) { 39 | this.latch = latch; 40 | } 41 | public void run() { 42 | try { 43 | latch.await(); 44 | print("Latch barrier passed for " + this); 45 | } catch(InterruptedException ex) { 46 | print(this + " interrupted"); 47 | } 48 | } 49 | public String toString() { 50 | return String.format("WaitingTask %1$-3d ", id); 51 | } 52 | } 53 | 54 | public class CountDownLatchDemo { 55 | static final int SIZE = 100; 56 | public static void main(String[] args) throws Exception { 57 | ExecutorService exec = Executors.newCachedThreadPool(); 58 | // All must share a single CountDownLatch object: 59 | CountDownLatch latch = new CountDownLatch(SIZE); 60 | for(int i = 0; i < 10; i++) 61 | exec.execute(new WaitingTask(latch)); 62 | for(int i = 0; i < SIZE; i++) 63 | exec.execute(new TaskPortion(latch)); 64 | print("Launched all tasks"); 65 | exec.shutdown(); // Quit when all tasks complete 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/CriticalSection.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.concurrent.ExecutorService; 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.TimeUnit; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | 11 | import static util.Print.print; 12 | 13 | class Pair { 14 | int x, y; 15 | public Pair(int x, int y) { 16 | this.x = x; 17 | this.y = y; 18 | } 19 | 20 | public Pair() { 21 | this(0, 0); 22 | } 23 | 24 | public int getX() { return x; } 25 | 26 | public int getY() { return y; } 27 | 28 | public void incrementX() { x++; } 29 | 30 | public void incrementY() { y++; } 31 | 32 | public String toString() { 33 | return "x: " + x + ", y: " + y; 34 | } 35 | 36 | public class PairValueNotEqualException 37 | extends RuntimeException { 38 | public PairValueNotEqualException() { 39 | super("Pair value not equal: " + Pair.this); 40 | } 41 | } 42 | 43 | public void checkState() { 44 | if (x != y) 45 | throw new PairValueNotEqualException(); 46 | } 47 | } 48 | 49 | abstract class PairManager { 50 | protected Pair p = new Pair(); 51 | AtomicInteger checkCounter = new AtomicInteger(0); 52 | private List storage = Collections.synchronizedList(new ArrayList()); 53 | 54 | public synchronized Pair getPair() { 55 | return new Pair(p.x, p.y); 56 | } 57 | 58 | public void store(Pair p) { 59 | storage.add(p); 60 | try { 61 | TimeUnit.MILLISECONDS.sleep(50); 62 | } catch (InterruptedException e) { 63 | e.printStackTrace(); 64 | } 65 | } 66 | 67 | public abstract void increment(); 68 | } 69 | 70 | class PairManager1 extends PairManager { 71 | @Override 72 | public synchronized void increment() { 73 | p.incrementX(); 74 | p.incrementY(); 75 | checkCounter.incrementAndGet(); 76 | p.checkState(); 77 | store(getPair()); 78 | } 79 | } 80 | 81 | class PairManager2 extends PairManager { 82 | @Override 83 | public void increment() { 84 | Pair temp = null; 85 | synchronized (this) { 86 | p.incrementX(); 87 | p.incrementY(); 88 | checkCounter.incrementAndGet(); 89 | p.checkState(); 90 | temp = getPair(); 91 | } 92 | store(temp); 93 | } 94 | } 95 | 96 | class PairManipulator implements Runnable{ 97 | private PairManager pm; 98 | public PairManipulator(PairManager pm) { 99 | this.pm = pm; 100 | } 101 | 102 | @Override 103 | public void run() { 104 | while(true) 105 | pm.increment(); 106 | } 107 | 108 | @Override 109 | public String toString() { 110 | return "Pair " + pm.getPair() + 111 | ", checkCounter = " + pm.checkCounter.get(); 112 | } 113 | } 114 | public class CriticalSection { 115 | static void testTwoApproaches(PairManager pm1, PairManager pm2) { 116 | ExecutorService exec = Executors.newCachedThreadPool(); 117 | PairManipulator manipulator1 = new PairManipulator(pm1); 118 | PairManipulator manipulator2 = new PairManipulator(pm2); 119 | 120 | exec.execute(manipulator1); 121 | exec.execute(manipulator2); 122 | 123 | try { 124 | TimeUnit.MILLISECONDS.sleep(500); 125 | } catch (InterruptedException e) { 126 | e.printStackTrace(); 127 | } 128 | 129 | print("manipulator1 " + manipulator1 + 130 | ", manipulator2 " + manipulator2); 131 | System.exit(0); 132 | } 133 | 134 | public static void main(String[] args) { 135 | PairManager 136 | pm1 = new PairManager1(), 137 | pm2 = new PairManager2(); 138 | 139 | testTwoApproaches(pm1, pm2); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/DaemonFromFactory.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import util.DaemonThreadFactory; 4 | 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | public class DaemonFromFactory { 10 | public static void main(String[] args) throws InterruptedException { 11 | ExecutorService exec = Executors.newCachedThreadPool(new DaemonThreadFactory()); 12 | for (int i = 0; i < 10; i++) { 13 | exec.execute(new SimpleDaemons()); 14 | } 15 | System.out.println("All daemons started"); 16 | TimeUnit.MILLISECONDS.sleep(100); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Daemons.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | class Daemon implements Runnable { 6 | Thread[] threads = new Thread[10]; 7 | @Override 8 | public void run() { 9 | for (int i = 0; i < threads.length; i++) { 10 | threads[i] = new Thread(new DaemonSpawn()); 11 | threads[i].start(); 12 | System.out.println("Daemon " + i + " started"); 13 | } 14 | 15 | for (int i = 0; i < threads.length; i++) { 16 | System.out.println("Daemon " + i + " is daemon: " + threads[i].isDaemon()); 17 | } 18 | } 19 | } 20 | 21 | class DaemonSpawn implements Runnable { 22 | 23 | @Override 24 | public void run() { 25 | while(true) { 26 | Thread.yield(); 27 | } 28 | } 29 | } 30 | public class Daemons { 31 | public static void main(String[] args) throws InterruptedException { 32 | Thread t = new Thread(new Daemon()); 33 | // All the sub threads will be daemon 34 | t.setDaemon(true); 35 | t.start(); 36 | 37 | System.out.println("t.isDaemon() " + t.isDaemon()); 38 | //TimeUnit.SECONDS.sleep(1); 39 | TimeUnit.NANOSECONDS.sleep(10); 40 | } 41 | }/* Output 42 | t.isDaemon() true 43 | Daemon 0 started 44 | Daemon 1 started 45 | Daemon 2 started 46 | Daemon 3 started 47 | Daemon 4 started 48 | Daemon 5 started 49 | Daemon 6 started 50 | Daemon 7 started 51 | Daemon 8 started 52 | Daemon 9 started 53 | Daemon 0 is daemon: true 54 | Daemon 1 is daemon: true 55 | Daemon 2 is daemon: true 56 | Daemon 3 is daemon: true 57 | Daemon 4 is daemon: true 58 | Daemon 5 is daemon: true 59 | Daemon 6 is daemon: true 60 | Daemon 7 is daemon: true 61 | Daemon 8 is daemon: true 62 | Daemon 9 is daemon: true 63 | 64 | Process finished with exit code 0 65 | */ 66 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/DaemonsDontRunFinally.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import static util.Print.print; 6 | 7 | class ADaemon implements Runnable { 8 | public void run() { 9 | try { 10 | print("Starting ADaemon"); 11 | TimeUnit.SECONDS.sleep(1); 12 | } catch(InterruptedException e) { 13 | print("Exiting via InterruptedException"); 14 | } finally { 15 | print("This should always run?"); 16 | } 17 | } 18 | } 19 | 20 | public class DaemonsDontRunFinally { 21 | public static void main(String[] args) throws Exception { 22 | Thread t = new Thread(new ADaemon()); 23 | t.setDaemon(true); 24 | t.start(); 25 | } 26 | } /* Output: 27 | Starting ADaemon 28 | */ 29 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/DeadlockingDiningPhilosophers.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.io.IOException; 4 | import java.util.concurrent.*; 5 | 6 | import static util.Print.print; 7 | 8 | class Chopstick{ 9 | private boolean taken = false; 10 | 11 | public synchronized void take() throws InterruptedException { 12 | while (taken) 13 | wait(); 14 | 15 | taken = true; 16 | } 17 | 18 | public synchronized void drop() { 19 | taken = false; 20 | notifyAll(); 21 | } 22 | } 23 | 24 | class Philosopher implements Runnable{ 25 | private Chopstick left; 26 | private Chopstick right; 27 | private final int id; 28 | private ThreadLocalRandom random = ThreadLocalRandom.current(); 29 | 30 | public Philosopher(Chopstick left, 31 | Chopstick right, 32 | int id) { 33 | this.left = left; 34 | this.right = right; 35 | this.id = id; 36 | } 37 | 38 | public void pause() throws InterruptedException { 39 | TimeUnit.MILLISECONDS.sleep(random.nextInt(300)); 40 | } 41 | 42 | @Override 43 | public void run() { 44 | try { 45 | while (!Thread.interrupted()) { 46 | print(this + " is thinking"); 47 | pause(); 48 | 49 | print(this + " grabbing left"); 50 | left.take(); 51 | 52 | // 增加死锁的概率 53 | pause(); 54 | 55 | print(this + " grabbing right"); 56 | right.take(); 57 | 58 | // Eat 59 | print(this + " is eating"); 60 | pause(); 61 | 62 | print(this + " dropping both chopsticks"); 63 | left.drop(); 64 | right.drop(); 65 | } 66 | } catch (InterruptedException e) { 67 | print("Philosopher run() was interrupted"); 68 | } 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | return "Philosopher " + id; 74 | } 75 | } 76 | public class DeadlockingDiningPhilosophers { 77 | public static void main(String[] args) throws IOException { 78 | int size = 5; 79 | Chopstick[] chopsticks = new Chopstick[size]; 80 | for (int i = 0; i < size; i++) { 81 | chopsticks[i] = new Chopstick(); 82 | } 83 | 84 | ExecutorService exec = Executors.newCachedThreadPool(); 85 | for (int i = 0; i < size; i++) { 86 | exec.execute(new Philosopher(chopsticks[i], chopsticks[(i + 1) % size], i)); 87 | } 88 | 89 | try { 90 | TimeUnit.SECONDS.sleep(5); 91 | } catch (InterruptedException e) { 92 | e.printStackTrace(); 93 | } 94 | exec.shutdownNow(); 95 | } 96 | }/* Output 97 | Philosopher 1 is thinking 98 | Philosopher 0 is thinking 99 | Philosopher 4 is thinking 100 | Philosopher 2 is thinking 101 | Philosopher 3 is thinking 102 | Philosopher 1 grabbing left 103 | Philosopher 3 grabbing left 104 | Philosopher 4 grabbing left 105 | Philosopher 0 grabbing left 106 | Philosopher 2 grabbing left 107 | Philosopher 1 grabbing right 108 | Philosopher 4 grabbing right 109 | Philosopher 3 grabbing right 110 | Philosopher 0 grabbing right 111 | Philosopher 2 grabbing right 112 | Philosopher run() was interrupted 113 | Philosopher run() was interrupted 114 | Philosopher run() was interrupted 115 | Philosopher run() was interrupted 116 | Philosopher run() was interrupted 117 | */ 118 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/DualSync.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import static util.Print.print; 4 | 5 | public class DualSync { 6 | private Object syncObj = new Object(); 7 | private static final int LOOP_SIZE = 10; 8 | public synchronized void f() { 9 | for (int i = 0; i < LOOP_SIZE; i++) { 10 | print("f()"); 11 | Thread.yield(); 12 | } 13 | } 14 | 15 | public void g() { 16 | synchronized (syncObj) { 17 | for (int i = 0; i < LOOP_SIZE; i++) { 18 | print("g()"); 19 | Thread.yield(); 20 | } 21 | } 22 | } 23 | 24 | public static void main(String[] args) { 25 | DualSync ds = new DualSync(); 26 | new Thread(() -> ds.f()).start(); 27 | 28 | ds.g(); 29 | } 30 | }/* Output 31 | g() 32 | f() 33 | f() 34 | f() 35 | g() 36 | g() 37 | f() 38 | g() 39 | g() 40 | g() 41 | g() 42 | g() 43 | g() 44 | g() 45 | f() 46 | f() 47 | f() 48 | f() 49 | f() 50 | f() 51 | */ -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/EvenChecker.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | import static util.Print.print; 7 | 8 | public class EvenChecker implements Runnable { 9 | private IntGenerator generator; 10 | private final int id; 11 | 12 | public EvenChecker(IntGenerator generator, int id) { 13 | this.generator = generator; 14 | this.id = id; 15 | } 16 | 17 | @Override 18 | public void run() { 19 | while (!generator.isCancel()) { 20 | int val = generator.next(); 21 | if (val % 2 == 1) { 22 | print(val + " is not even!"); 23 | generator.cancel(); 24 | } 25 | } 26 | } 27 | 28 | public static void test(IntGenerator generator, int threadCount) { 29 | ExecutorService exec = Executors.newCachedThreadPool(); 30 | for (int i = 0; i < threadCount; i++) { 31 | exec.execute(new EvenChecker(generator, i)); 32 | } 33 | exec.shutdown(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/EvenGenerator.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | public class EvenGenerator extends IntGenerator { 4 | private int currentEvenValue = 0; 5 | @Override 6 | public int next() { 7 | ++currentEvenValue; // Danger point!! 8 | ++currentEvenValue; 9 | return currentEvenValue; 10 | } 11 | 12 | public static void main(String[] args) { 13 | EvenChecker.test(new EvenGenerator(), 10); 14 | } 15 | } /* Output 16 | 987 is not even! 17 | 991 is not even! 18 | 981 is not even! 19 | 989 is not even! 20 | 985 is not even! 21 | 983 is not even! 22 | 979 is not even! 23 | */ 24 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex14Timer.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.Timer; 4 | import java.util.TimerTask; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | public class Ex14Timer implements Runnable{ 10 | private static int timers = 0; 11 | private static int tasks = 0; 12 | public void run() { 13 | try { 14 | while(timers < 2000) { // create 2000 Timers 15 | ++timers; 16 | Timer t = new Timer(); 17 | t.schedule(new TimerTask() { 18 | public void run() { 19 | ++tasks; 20 | if(timers % 100 == 0) 21 | System.out.println(timers + " timers did " 22 | + tasks + " tasks"); 23 | } 24 | }, 0); 25 | try { 26 | TimeUnit.MILLISECONDS.sleep(30); // time to do task 27 | } catch(InterruptedException e) { 28 | System.out.println("Sleep interrupted"); 29 | } 30 | t.cancel(); 31 | } 32 | } finally { 33 | System.out.println("Done. " + timers + " timers completed " 34 | + tasks + " tasks"); 35 | } 36 | } 37 | public static void main(String[] args) { 38 | ExecutorService exec = Executors.newCachedThreadPool(); 39 | exec.execute(new Ex14Timer()); 40 | exec.shutdown(); 41 | } 42 | } /* Output: 43 | 100 timers did 100 tasks 44 | 200 timers did 200 tasks 45 | 300 timers did 300 tasks 46 | 400 timers did 400 tasks 47 | 500 timers did 500 tasks 48 | 600 timers did 600 tasks 49 | 700 timers did 700 tasks 50 | 800 timers did 800 tasks 51 | 900 timers did 900 tasks 52 | 1000 timers did 1000 tasks 53 | 1100 timers did 1100 tasks 54 | 1200 timers did 1200 tasks 55 | 1300 timers did 1300 tasks 56 | 1400 timers did 1400 tasks 57 | 1500 timers did 1500 tasks 58 | 1600 timers did 1600 tasks 59 | 1700 timers did 1700 tasks 60 | 1800 timers did 1800 tasks 61 | 1900 timers did 1900 tasks 62 | 2000 timers did 2000 tasks 63 | Done. 2000 timers completed 2000 tasks 64 | */ -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex15SyncTest.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import static util.Print.print; 4 | 5 | class SyncTest1 { 6 | private static final int LOOP_SIZE = 10; 7 | public void f1() { 8 | synchronized (this) { 9 | for (int i = 0; i < LOOP_SIZE; i++) { 10 | print("f1()"); 11 | Thread.yield(); 12 | } 13 | } 14 | } 15 | 16 | public void g1() { 17 | synchronized (this) { 18 | for (int i = 0; i < LOOP_SIZE; i++) { 19 | print("g1()"); 20 | Thread.yield(); 21 | } 22 | } 23 | } 24 | 25 | public void h1() { 26 | synchronized (this) { 27 | for (int i = 0; i < LOOP_SIZE; i++) { 28 | print("h1()"); 29 | Thread.yield(); 30 | } 31 | } 32 | } 33 | } 34 | 35 | class SyncTest2 { 36 | private static final int LOOP_SIZE = 10; 37 | private Object syncObj1 = new Object(); 38 | private Object syncObj2 = new Object(); 39 | private Object syncObj3 = new Object(); 40 | 41 | public void f2() { 42 | synchronized (syncObj1) { 43 | for (int i = 0; i < LOOP_SIZE; i++) { 44 | print("f2()"); 45 | Thread.yield(); 46 | } 47 | } 48 | } 49 | 50 | public void g2() { 51 | synchronized (syncObj2) { 52 | for (int i = 0; i < LOOP_SIZE; i++) { 53 | print("g2()"); 54 | Thread.yield(); 55 | } 56 | } 57 | } 58 | 59 | public void h2() { 60 | synchronized (syncObj3) { 61 | for (int i = 0; i < LOOP_SIZE; i++) { 62 | print("h2()"); 63 | Thread.yield(); 64 | } 65 | } 66 | } 67 | } 68 | public class Ex15SyncTest { 69 | public static void main(String[] args) { 70 | SyncTest1 st1 = new SyncTest1(); 71 | SyncTest2 st2 = new SyncTest2(); 72 | 73 | new Thread(() -> st1.f1()).start(); 74 | new Thread(() -> st1.g1()).start(); 75 | new Thread(() -> st1.h1()).start(); 76 | 77 | new Thread(() -> st2.f2()).start(); 78 | new Thread(() -> st2.g2()).start(); 79 | new Thread(() -> st2.h2()).start(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex16LockTest.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | import static util.Print.print; 7 | 8 | class LockTest1 { // all methods use same lock 9 | private Lock lock = new ReentrantLock(); 10 | public void f1() { 11 | lock.lock(); 12 | try { 13 | for(int i = 0; i < 5; i++) { 14 | print("f1()"); 15 | Thread.yield(); 16 | } 17 | } finally { 18 | lock.unlock(); 19 | } 20 | } 21 | public void g1() { 22 | lock.lock(); 23 | try { 24 | for(int i = 0; i < 5; i++) { 25 | print("g1()"); 26 | Thread.yield(); 27 | } 28 | } finally { 29 | lock.unlock(); 30 | } 31 | } 32 | public void h1() { 33 | lock.lock(); 34 | try { 35 | for(int i = 0; i < 5; i++) { 36 | print("h1()"); 37 | Thread.yield(); 38 | } 39 | } finally { 40 | lock.unlock(); 41 | } 42 | } 43 | } 44 | 45 | class LockTest2 { // each method has a different lock 46 | private Lock lock1 = new ReentrantLock(); 47 | private Lock lock2 = new ReentrantLock(); 48 | private Lock lock3 = new ReentrantLock(); 49 | 50 | public void f2() { 51 | lock1.lock(); 52 | try { 53 | for(int i = 0; i < 5; i++) { 54 | print("f2()"); 55 | Thread.yield(); 56 | } 57 | } finally { 58 | lock1.unlock(); 59 | } 60 | } 61 | public void g2() { 62 | lock2.lock(); 63 | try { 64 | for(int i = 0; i < 5; i++) { 65 | print("g2()"); 66 | Thread.yield(); 67 | } 68 | } finally { 69 | lock2.unlock(); 70 | } 71 | } 72 | public void h2() { 73 | lock3.lock(); 74 | try { 75 | for(int i = 0; i < 5; i++) { 76 | print("h2()"); 77 | Thread.yield(); 78 | } 79 | } finally { 80 | lock3.unlock(); 81 | } 82 | } 83 | } 84 | public class Ex16LockTest { 85 | public static void main(String[] args) { 86 | LockTest1 st1 = new LockTest1(); 87 | LockTest2 st2 = new LockTest2(); 88 | 89 | new Thread(() -> st1.f1()).start(); 90 | new Thread(() -> st1.g1()).start(); 91 | new Thread(() -> st1.h1()).start(); 92 | 93 | new Thread(() -> st2.f2()).start(); 94 | new Thread(() -> st2.g2()).start(); 95 | new Thread(() -> st2.h2()).start(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex18Interruption.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.*; 4 | 5 | import static util.Print.print; 6 | 7 | class NonTask { 8 | public static void rest() { 9 | try { 10 | print("I'm gonna sleep"); 11 | TimeUnit.SECONDS.sleep(5); 12 | } catch (InterruptedException e) { 13 | print("Sleep interrupted"); 14 | } finally { 15 | print("Good Bye!"); 16 | } 17 | } 18 | } 19 | 20 | class Worker implements Runnable { 21 | @Override 22 | public void run() { 23 | NonTask.rest(); 24 | } 25 | } 26 | public class Ex18Interruption { 27 | public static void main(String[] args) throws InterruptedException { 28 | // 3 ways to do it 29 | Thread t = new Thread(new Worker()); 30 | t.start(); 31 | TimeUnit.MILLISECONDS.sleep(100); 32 | t.interrupt(); 33 | 34 | ExecutorService exec = Executors.newCachedThreadPool(); 35 | exec.execute(new Worker()); 36 | TimeUnit.MILLISECONDS.sleep(100); 37 | exec.shutdownNow(); 38 | 39 | ExecutorService exec2 = Executors.newCachedThreadPool(); 40 | Future f = exec2.submit(new Worker()); 41 | TimeUnit.MILLISECONDS.sleep(100); 42 | f.cancel(true); 43 | //exec2.shutdown(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex1Runner.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | public class Ex1Runner implements Runnable { 4 | private static int runnerCount = 0; 5 | private final int runnerId = runnerCount++; 6 | 7 | public Ex1Runner() { 8 | System.out.println("Constructing Runner " + runnerId); 9 | } 10 | 11 | @Override 12 | public void run() { 13 | for (int i = 0;i < 3; i++) { 14 | System.out.println("Hi from Runner " + runnerId); 15 | Thread.yield(); 16 | } 17 | System.out.println("Completing Runner " + runnerId); 18 | } 19 | 20 | public static void main(String[] args) { 21 | for (int i = 0; i < 10; i++) { 22 | new Thread(new Ex1Runner()).start(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex21WaitAndNotify.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import static util.Print.print; 9 | 10 | class WaitTask implements Runnable { 11 | @Override 12 | // synchronized is necessary because call to wait() has to be inside 13 | // a synchronized method or block 14 | public synchronized void run() { 15 | try { 16 | wait(); 17 | } catch (InterruptedException e) { 18 | print("WaitTask is interrupted"); 19 | return; 20 | } 21 | print("WaitTask received notification"); 22 | } 23 | } 24 | 25 | class NotifyTask implements Runnable { 26 | private Runnable task; 27 | public NotifyTask(Runnable task) { 28 | this.task = task; 29 | } 30 | 31 | @Override 32 | public void run() { 33 | try { 34 | TimeUnit.SECONDS.sleep(1); 35 | print("Notifying task " + task.getClass().getSimpleName()); 36 | // synchronized is necessary because call to notifyAll() has to be inside 37 | // a synchronized method or block of the object 38 | synchronized (task) { 39 | //task.notifyAll(); 40 | task.notify(); 41 | } 42 | } catch (InterruptedException e) { 43 | print("NotifyTask is interrupted"); 44 | } 45 | } 46 | } 47 | public class Ex21WaitAndNotify { 48 | public static void main(String[] args) { 49 | ExecutorService exec = Executors.newCachedThreadPool(); 50 | WaitTask wt = new WaitTask(); 51 | exec.execute(wt); 52 | exec.execute(new NotifyTask(wt)); 53 | 54 | exec.shutdown(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex22BusyWaitAndBetterWait.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import static util.Print.print; 9 | 10 | class FlagTask implements Runnable { 11 | private boolean flag = false; 12 | @Override 13 | public synchronized void run() { 14 | try { 15 | TimeUnit.SECONDS.sleep(3); 16 | } catch (InterruptedException e) { 17 | print("Sleep was interrupted in FlagTask"); 18 | } 19 | print("Setting flag = true"); 20 | flag = true; 21 | } 22 | 23 | public synchronized boolean getFlag() { 24 | return flag; 25 | } 26 | } 27 | 28 | class BusyWait implements Runnable { 29 | private FlagTask task; 30 | public BusyWait(FlagTask r) { 31 | this.task = r; 32 | } 33 | 34 | @Override 35 | public void run() { 36 | long start = System.nanoTime(); 37 | while(!Thread.interrupted()) { 38 | if (!task.getFlag()) 39 | continue; 40 | print("FlagTask flag set to true!"); 41 | long end = System.nanoTime(); 42 | print("Busy waited " + (end - start) + " nanoseconds"); 43 | break; 44 | } 45 | } 46 | 47 | } 48 | 49 | class BetterWait implements Runnable { 50 | private FlagTask task; 51 | public BetterWait(FlagTask task) { 52 | this.task = task; 53 | } 54 | 55 | @Override 56 | public void run() { 57 | try { 58 | while(!task.getFlag()) { 59 | wait(); 60 | } 61 | print("FlagTask flag set to true!"); 62 | } catch (InterruptedException e) { 63 | print("Wait was interrupted"); 64 | } 65 | } 66 | } 67 | public class Ex22BusyWaitAndBetterWait { 68 | public static void main(String[] args) { 69 | ExecutorService exec = Executors.newCachedThreadPool(); 70 | FlagTask ft = new FlagTask(); 71 | BusyWait busyWait = new BusyWait(ft); 72 | exec.execute(busyWait); 73 | exec.execute(ft); 74 | 75 | try { 76 | TimeUnit.SECONDS.sleep(5); 77 | } catch (InterruptedException e) { 78 | print("Sleep was interrupted in main"); 79 | } 80 | 81 | FlagTask ft2 = new FlagTask(); 82 | BetterWait betterWait = new BetterWait(ft2); 83 | exec.execute(betterWait); 84 | exec.execute(ft2); 85 | 86 | print(); 87 | try { 88 | TimeUnit.SECONDS.sleep(5); 89 | } catch (InterruptedException e) { 90 | print("Sleep was interrupted in main"); 91 | } 92 | 93 | exec.shutdown(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex27Restaurant.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.*; 4 | import java.util.concurrent.locks.*; 5 | 6 | import static util.Print.print; 7 | import static util.Print.printnb; 8 | 9 | class WaitPerson27 implements Runnable { 10 | private Ex27Restaurant restaurant; 11 | protected Lock lock = new ReentrantLock(); 12 | protected Condition condition = lock.newCondition(); 13 | public WaitPerson27(Ex27Restaurant r) { restaurant = r; } 14 | public void run() { 15 | try { 16 | while(!Thread.interrupted()) { 17 | lock.lock(); 18 | try { 19 | while(restaurant.meal == null) 20 | condition.await(); 21 | } finally { 22 | lock.unlock(); 23 | } 24 | print("waitPerson got " + restaurant.meal); 25 | restaurant.chef.lock.lock(); 26 | try { 27 | restaurant.meal = null; 28 | restaurant.chef.condition.signalAll(); 29 | } finally { 30 | restaurant.chef.lock.unlock(); 31 | } 32 | } 33 | } catch(InterruptedException e) { 34 | print("WaitPerson27 interrupted"); 35 | } 36 | } 37 | } 38 | 39 | class Chef27 implements Runnable { 40 | private Ex27Restaurant restaurant; 41 | private int count = 0; 42 | protected Lock lock = new ReentrantLock(); 43 | protected Condition condition = lock.newCondition(); 44 | public Chef27(Ex27Restaurant r) { restaurant = r; } 45 | public void run() { 46 | try { 47 | while(!Thread.interrupted()) { 48 | lock.lock(); 49 | try { 50 | while(restaurant.meal != null) 51 | condition.await(); 52 | } finally { 53 | lock.unlock(); 54 | } 55 | if(++count == 10) { 56 | print("Out of food, closing"); 57 | restaurant.exec.shutdownNow(); 58 | return; 59 | } 60 | printnb("Order up! "); 61 | restaurant.waitPerson.lock.lock(); 62 | try { 63 | restaurant.meal = new Meal(count); 64 | restaurant.waitPerson.condition.signalAll(); 65 | } finally { 66 | restaurant.waitPerson.lock.unlock(); 67 | } 68 | TimeUnit.MILLISECONDS.sleep(100); 69 | } 70 | } catch(InterruptedException e) { 71 | print("chef interrupted"); 72 | } 73 | } 74 | } 75 | 76 | public class Ex27Restaurant { 77 | Meal meal; 78 | ExecutorService exec = Executors.newCachedThreadPool(); 79 | WaitPerson27 waitPerson = new WaitPerson27(this); 80 | Chef27 chef = new Chef27(this); 81 | public Ex27Restaurant() { 82 | exec.execute(chef); 83 | exec.execute(waitPerson); 84 | } 85 | public static void main(String[] args) { 86 | new Ex27Restaurant(); 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex30PipeIOUsingBlockingQueue.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.*; 4 | 5 | import static util.Print.print; 6 | import static util.Print.printnb; 7 | 8 | class Sender implements Runnable { 9 | private BlockingQueue queue; 10 | public Sender(BlockingQueue queue) { 11 | this.queue = queue; 12 | } 13 | 14 | @Override 15 | public void run() { 16 | try { 17 | while(!Thread.interrupted()) { 18 | for(char c = 'A'; c <= 'Z'; c++) { 19 | queue.put(c); 20 | TimeUnit.MILLISECONDS.sleep(500); 21 | } 22 | } 23 | } catch (InterruptedException e) { 24 | print("Sender run() was interrupted"); 25 | } 26 | print("Exiting Sender ()"); 27 | } 28 | } 29 | 30 | class Receiver implements Runnable { 31 | private BlockingQueue queue; 32 | public Receiver(BlockingQueue queue) { 33 | this.queue = queue; 34 | } 35 | 36 | @Override 37 | public void run() { 38 | try { 39 | while(!Thread.interrupted()) { 40 | print("Read :" + queue.take()); 41 | } 42 | } catch (InterruptedException e) { 43 | print("Interrupted BlockingQueue.take()"); 44 | } 45 | print("Exiting Receiver run()"); 46 | } 47 | } 48 | public class Ex30PipeIOUsingBlockingQueue { 49 | public static void main(String[] args) throws InterruptedException { 50 | ExecutorService exec = Executors.newCachedThreadPool(); 51 | //BlockingQueue queue = new LinkedBlockingDeque<>(); 52 | BlockingQueue queue = new ArrayBlockingQueue(3); 53 | exec.execute(new Sender(queue)); 54 | TimeUnit.SECONDS.sleep(3); 55 | exec.execute(new Receiver(queue)); 56 | 57 | TimeUnit.SECONDS.sleep(3); 58 | exec.shutdownNow(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex5FibonacciCallable.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.concurrent.*; 7 | 8 | public class Ex5FibonacciCallable implements Callable>{ 9 | private int[] fibonacciCache; 10 | private int size; 11 | public Ex5FibonacciCallable(int size) { 12 | if (size <= 0) 13 | throw new IllegalArgumentException(); 14 | 15 | this.size = size; 16 | fibonacciCache = new int[size]; 17 | fibonacciCache[0] = 1; 18 | if (size > 1) 19 | fibonacciCache[1] = 1; 20 | } 21 | 22 | private int get(int position) { 23 | if (position < 0) 24 | throw new IllegalArgumentException(); 25 | if (position < 2) 26 | return fibonacciCache[position]; 27 | 28 | if (fibonacciCache[position] != 0) 29 | return fibonacciCache[position]; 30 | 31 | int first = get(position - 2); 32 | int second = get(position - 1); 33 | int result = first + second; 34 | fibonacciCache[position] = result; 35 | 36 | return result; 37 | } 38 | 39 | 40 | @Override 41 | public ArrayList call() throws Exception { 42 | ArrayList result = new ArrayList<>(); 43 | get(size - 1); 44 | for (int i = 0; i < size; i++) { 45 | result.add(fibonacciCache[i]); 46 | } 47 | return result; 48 | } 49 | 50 | public static void main(String[] args) { 51 | ArrayList>> results = new ArrayList<>(); 52 | ExecutorService executor = Executors.newCachedThreadPool(); 53 | for (int i = 1; i <= 10; i++) { 54 | results.add(executor.submit(new Ex5FibonacciCallable(i))); 55 | } 56 | 57 | for (Future> result: results) { 58 | try { 59 | System.out.println(result.get()); 60 | } catch (InterruptedException e) { 61 | e.printStackTrace(); 62 | } catch (ExecutionException e) { 63 | e.printStackTrace(); 64 | } finally { 65 | executor.shutdown(); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Ex6RandomSleep.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.*; 4 | 5 | public class Ex6RandomSleep implements Runnable{ 6 | 7 | @Override 8 | public void run() { 9 | long startTime = System.currentTimeMillis(); 10 | try { 11 | TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(1, 10)); 12 | } catch (InterruptedException e) { 13 | e.printStackTrace(); 14 | } 15 | long duration = System.currentTimeMillis() - startTime; 16 | System.out.println("Slept " + duration / 1000 + " seconds"); 17 | } 18 | 19 | public static void main(String[] args) { 20 | ExecutorService exec = Executors.newCachedThreadPool(); 21 | for (int i = 0; i < 5; i++) { 22 | exec.execute(new Ex6RandomSleep()); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/ExceptionThread.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | public class ExceptionThread implements Runnable { 7 | @Override 8 | public void run() { 9 | throw new RuntimeException(); 10 | } 11 | 12 | public static void main(String[] args) { 13 | new Thread(new ExceptionThread()).start(); 14 | 15 | ExecutorService exec = Executors.newCachedThreadPool(); 16 | exec.execute(new ExceptionThread()); 17 | } 18 | }/* Output 19 | Exception in thread "Thread-0" java.lang.RuntimeException 20 | at ch21concurrency.ExceptionThread.run(ExceptionThread.java:9) 21 | at java.lang.Thread.run(Thread.java:745) 22 | Exception in thread "pool-1-thread-1" java.lang.RuntimeException 23 | at ch21concurrency.ExceptionThread.run(ExceptionThread.java:9) 24 | at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 25 | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 26 | at java.lang.Thread.run(Thread.java:745) 27 | */ -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/FixedDiningPhilosophers.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | public class FixedDiningPhilosophers { 8 | public static void main(String[] args) { 9 | int size = 5; 10 | Chopstick[] chopsticks = new Chopstick[size]; 11 | for (int i = 0; i < size; i++) { 12 | chopsticks[i] = new Chopstick(); 13 | } 14 | 15 | ExecutorService exec = Executors.newCachedThreadPool(); 16 | for (int i = 0; i < size; i++) { 17 | if(i < size - 1) 18 | exec.execute(new Philosopher(chopsticks[i], chopsticks[(i + 1) % size], i)); 19 | else 20 | // 让最后一位哲学家以相反的顺序拿筷子可防止死锁 21 | exec.execute(new Philosopher(chopsticks[(i + 1) % size], chopsticks[i], i)); 22 | } 23 | 24 | try { 25 | TimeUnit.SECONDS.sleep(5); 26 | } catch (InterruptedException e) { 27 | e.printStackTrace(); 28 | } 29 | exec.shutdownNow(); 30 | } 31 | }/* Output 32 | 无死锁 33 | */ 34 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/FixedThreadPool.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | public class FixedThreadPool { 7 | public static void main(String[] args) { 8 | ExecutorService executor = Executors.newFixedThreadPool(5); 9 | for (int i = 0; i < 5; i++) { 10 | executor.execute(new LiftOff()); 11 | } 12 | executor.shutdown(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/HorseRace.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | import java.util.concurrent.*; 3 | import java.util.*; 4 | import static util.Print.print; 5 | 6 | class Horse implements Runnable { 7 | private static int counter = 0; 8 | private final int id = counter++; 9 | private int strides = 0; 10 | private static Random rand = new Random(47); 11 | private static CyclicBarrier barrier; 12 | public Horse(CyclicBarrier b) { barrier = b; } 13 | public synchronized int getStrides() { return strides; } 14 | public void run() { 15 | try { 16 | while(!Thread.interrupted()) { 17 | synchronized(this) { 18 | strides += rand.nextInt(3); // Produces 0, 1 or 2 19 | } 20 | barrier.await(); 21 | } 22 | } catch(InterruptedException e) { 23 | // A legitimate way to exit 24 | } catch(BrokenBarrierException e) { 25 | // This one we want to know about 26 | throw new RuntimeException(e); 27 | } 28 | } 29 | public String toString() { return "Horse " + id + " "; } 30 | public String tracks() { 31 | StringBuilder s = new StringBuilder(); 32 | for(int i = 0; i < getStrides(); i++) 33 | s.append("*"); 34 | s.append(id); 35 | return s.toString(); 36 | } 37 | } 38 | 39 | public class HorseRace { 40 | static final int FINISH_LINE = 75; 41 | private List horses = new ArrayList(); 42 | private ExecutorService exec = 43 | Executors.newCachedThreadPool(); 44 | private CyclicBarrier barrier; 45 | public HorseRace(int nHorses, final int pause) { 46 | barrier = new CyclicBarrier(nHorses, new Runnable() { 47 | public void run() { 48 | StringBuilder s = new StringBuilder(); 49 | for(int i = 0; i < FINISH_LINE; i++) 50 | s.append("="); // The fence on the racetrack 51 | print(s); 52 | for(Horse horse : horses) 53 | print(horse.tracks()); 54 | for(Horse horse : horses) 55 | if(horse.getStrides() >= FINISH_LINE) { 56 | print(horse + "won!"); 57 | exec.shutdownNow(); 58 | return; 59 | } 60 | try { 61 | TimeUnit.MILLISECONDS.sleep(pause); 62 | } catch(InterruptedException e) { 63 | print("barrier-action sleep interrupted"); 64 | } 65 | } 66 | }); 67 | for(int i = 0; i < nHorses; i++) { 68 | Horse horse = new Horse(barrier); 69 | horses.add(horse); 70 | exec.execute(horse); 71 | } 72 | } 73 | public static void main(String[] args) { 74 | int nHorses = 7; 75 | int pause = 200; 76 | if(args.length > 0) { // Optional argument 77 | int n = new Integer(args[0]); 78 | nHorses = n > 0 ? n : nHorses; 79 | } 80 | if(args.length > 1) { // Optional argument 81 | int p = new Integer(args[1]); 82 | pause = p > -1 ? p : pause; 83 | } 84 | new HorseRace(nHorses, pause); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/IntGenerator.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | public abstract class IntGenerator { 4 | private volatile boolean cancel = false; 5 | public abstract int next(); 6 | 7 | public void cancel() { 8 | cancel = true; 9 | } 10 | 11 | public boolean isCancel() { 12 | return cancel; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Interrupting.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.concurrent.*; 6 | 7 | import static util.Print.print; 8 | 9 | class SleepBlocked implements Runnable { 10 | private String className = getClass().getSimpleName() + " "; 11 | @Override 12 | public void run() { 13 | try { 14 | TimeUnit.MILLISECONDS.sleep(300); 15 | } catch (InterruptedException e) { 16 | print(className + "InterruptedException"); 17 | } 18 | print(className + "exiting run()"); 19 | } 20 | } 21 | 22 | class IOBlocked implements Runnable { 23 | private String className = getClass().getSimpleName() + " "; 24 | private InputStream is; 25 | 26 | public IOBlocked(InputStream in) { 27 | this.is = in; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | print(className + "waiting for read"); 33 | try { 34 | is.read(); 35 | } catch (IOException e) { 36 | if (Thread.currentThread().isInterrupted()) 37 | print(className + "interrupted"); 38 | else 39 | throw new RuntimeException(); 40 | } 41 | print(className + "exiting run()"); 42 | } 43 | } 44 | 45 | class SynchronizedBlocked implements Runnable { 46 | private String className = getClass().getSimpleName() + " "; 47 | 48 | public synchronized void f() { 49 | while(true) 50 | Thread.yield(); 51 | } 52 | 53 | public SynchronizedBlocked() { 54 | new Thread(() -> f()).start();; 55 | } 56 | 57 | @Override 58 | public void run() { 59 | print(className + "trying to call f()"); 60 | f(); 61 | print(className + "exiting run()"); 62 | } 63 | } 64 | public class Interrupting { 65 | private static ExecutorService exec = 66 | Executors.newCachedThreadPool(); 67 | 68 | static void test(Runnable r) throws InterruptedException { 69 | Future f = exec.submit(r); 70 | TimeUnit.MILLISECONDS.sleep(100); 71 | print("Interrupting " + r.getClass().getSimpleName()); 72 | f.cancel(true); 73 | print("Interrupt send to " + r.getClass().getSimpleName()); 74 | } 75 | 76 | public static void main(String[] args) throws InterruptedException { 77 | test(new SleepBlocked()); 78 | test(new IOBlocked(System.in)); 79 | test(new SynchronizedBlocked()); 80 | 81 | TimeUnit.MILLISECONDS.sleep(500); 82 | print("Aborting system"); 83 | System.exit(0); 84 | } 85 | }/* Output 86 | Interrupting SleepBlocked 87 | Interrupt send to SleepBlocked 88 | SleepBlocked InterruptedException 89 | SleepBlocked exiting run() 90 | IOBlocked waiting for read 91 | Interrupting IOBlocked 92 | Interrupt send to IOBlocked 93 | SynchronizedBlocked trying to call f() 94 | Interrupting SynchronizedBlocked 95 | Interrupt send to SynchronizedBlocked 96 | Aborting system 97 | */ 98 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Joining.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import static util.Print.print; 4 | 5 | class Sleeper extends Thread { 6 | private int duration; 7 | public Sleeper(String name, int duration) { 8 | super(name); 9 | this.duration = duration; 10 | start(); 11 | } 12 | 13 | @Override 14 | public void run() { 15 | try { 16 | sleep(duration); 17 | } catch (InterruptedException e) { 18 | System.out.println(getName() + " was interrupted. " + 19 | "isInterrupted() " + isInterrupted()); 20 | //e.printStackTrace(); 21 | return; 22 | } 23 | System.out.println(getName() + " has awaked."); 24 | } 25 | } 26 | 27 | class Joiner extends Thread { 28 | Sleeper sleeper; 29 | public Joiner(String name, Sleeper sleeper) { 30 | super(name); 31 | this.sleeper = sleeper; 32 | start(); 33 | } 34 | 35 | @Override 36 | public void run() { 37 | try { 38 | sleeper.join(); 39 | } catch (InterruptedException e) { 40 | print(getName() + "'s sleeper was interrupted "); 41 | e.printStackTrace(); 42 | } 43 | print(getName() + " is completed."); 44 | } 45 | } 46 | 47 | public class Joining { 48 | public static void main(String[] args) { 49 | Sleeper s1 = new Sleeper("s1", 1500); 50 | Sleeper s2 = new Sleeper("s2", 1500); 51 | 52 | Joiner j1 = new Joiner("j1", s1); 53 | Joiner j2 = new Joiner("j2", s2); 54 | 55 | s2.interrupt(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/LiftOff.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | public class LiftOff implements Runnable { 4 | protected int countDown = 10; // default 5 | private static int taskCount = 0; 6 | private final int id = taskCount++; 7 | 8 | public LiftOff() {} 9 | 10 | public LiftOff(int countDown) { 11 | this.countDown = countDown; 12 | } 13 | 14 | public String status() { 15 | return "#" + id + "(" + 16 | (countDown > 0 ? countDown : "Liftoff!") + "), "; 17 | } 18 | 19 | @Override 20 | public void run() { 21 | while (countDown > 0) { 22 | countDown--; 23 | System.out.print(status()); 24 | Thread.yield(); 25 | } 26 | } 27 | 28 | public static void main(String[] args) { 29 | LiftOff launch = new LiftOff(); 30 | launch.run(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/MoreBasicThreads.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | public class MoreBasicThreads { 4 | public static void main(String[] args) { 5 | for (int i = 0; i < 5; i++) { 6 | new Thread(new LiftOff()).start(); 7 | } 8 | System.out.println("Waiting for LiftOff"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/MutexEvenGenerator.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | public class MutexEvenGenerator extends IntGenerator { 7 | private int currentEvenValue = 0; 8 | private Lock lock = new ReentrantLock(); 9 | 10 | @Override 11 | public int next() { 12 | lock.lock(); 13 | try { 14 | ++currentEvenValue; 15 | Thread.yield(); // yield is safe, protecting by lock 16 | ++currentEvenValue; 17 | 18 | return currentEvenValue; 19 | } finally { 20 | lock.unlock(); 21 | } 22 | } 23 | 24 | public static void main(String[] args) { 25 | EvenChecker.test(new MutexEvenGenerator(), 10); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/NIOInterruption.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.io.IOException; 4 | import java.net.*; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.*; 7 | import java.util.concurrent.*; 8 | 9 | import static util.Print.print; 10 | 11 | class NIOBlocked implements Runnable { 12 | private final SocketChannel sc; 13 | public NIOBlocked(SocketChannel sc) { this.sc = sc; } 14 | public void run() { 15 | try { 16 | print("Waiting for read() in " + this); 17 | sc.read(ByteBuffer.allocate(1)); 18 | } catch(ClosedByInterruptException e) { 19 | print("ClosedByInterruptException"); 20 | } catch(AsynchronousCloseException e) { 21 | print("AsynchronousCloseException"); 22 | } catch(IOException e) { 23 | throw new RuntimeException(e); 24 | } 25 | print("Exiting NIOBlocked.run() " + this); 26 | } 27 | } 28 | 29 | public class NIOInterruption { 30 | public static void main(String[] args) throws Exception { 31 | ExecutorService exec = Executors.newCachedThreadPool(); 32 | ServerSocket server = new ServerSocket(8080); 33 | InetSocketAddress isa = 34 | new InetSocketAddress("localhost", 8080); 35 | SocketChannel sc1 = SocketChannel.open(isa); 36 | SocketChannel sc2 = SocketChannel.open(isa); 37 | Future f = exec.submit(new NIOBlocked(sc1)); 38 | exec.execute(new NIOBlocked(sc2)); 39 | exec.shutdown(); 40 | TimeUnit.SECONDS.sleep(1); 41 | // Produce an interrupt via cancel: 42 | f.cancel(true); 43 | TimeUnit.SECONDS.sleep(1); 44 | // Release the block by closing the channel: 45 | sc2.close(); 46 | } 47 | } /* Output: (Sample) 48 | Waiting for read() in NIOBlocked@7a84e4 49 | Waiting for read() in NIOBlocked@15c7850 50 | ClosedByInterruptException 51 | Exiting NIOBlocked.run() NIOBlocked@15c7850 52 | AsynchronousCloseException 53 | Exiting NIOBlocked.run() NIOBlocked@7a84e4 54 | */ 55 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/NaiveExceptionHandling.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | 7 | import static util.Print.print; 8 | 9 | public class NaiveExceptionHandling { 10 | public static void main(String[] args) { 11 | ExecutorService exec = Executors.newCachedThreadPool(); 12 | try { 13 | exec.execute(new ExceptionThread()); 14 | } catch (RuntimeException e) { 15 | print("Runtime Exception!"); 16 | e.printStackTrace(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/NotifyVsNotifyAll.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | import java.util.concurrent.*; 3 | import java.util.*; 4 | 5 | class Blocker { 6 | synchronized void waitingCall() { 7 | try { 8 | while(!Thread.interrupted()) { 9 | wait(); 10 | System.out.print(Thread.currentThread() + " "); 11 | } 12 | } catch(InterruptedException e) { 13 | // OK to exit this way 14 | } 15 | } 16 | synchronized void prod() { notify(); } 17 | synchronized void prodAll() { notifyAll(); } 18 | } 19 | 20 | class Task implements Runnable { 21 | static Blocker blocker = new Blocker(); 22 | public void run() { blocker.waitingCall(); } 23 | } 24 | 25 | class Task2 implements Runnable { 26 | // A separate Blocker object: 27 | static Blocker blocker = new Blocker(); 28 | public void run() { blocker.waitingCall(); } 29 | } 30 | 31 | public class NotifyVsNotifyAll { 32 | public static void main(String[] args) throws Exception { 33 | ExecutorService exec = Executors.newCachedThreadPool(); 34 | for(int i = 0; i < 5; i++) 35 | exec.execute(new Task()); 36 | exec.execute(new Task2()); 37 | Timer timer = new Timer(); 38 | timer.scheduleAtFixedRate(new TimerTask() { 39 | boolean prod = true; 40 | public void run() { 41 | if(prod) { 42 | System.out.print("\nnotify() "); 43 | Task.blocker.prod(); 44 | prod = false; 45 | } else { 46 | System.out.print("\nnotifyAll() "); 47 | Task.blocker.prodAll(); 48 | prod = true; 49 | } 50 | } 51 | }, 400, 400); // Run every .4 second 52 | TimeUnit.SECONDS.sleep(5); // Run for a while... 53 | timer.cancel(); 54 | System.out.println("\nTimer canceled"); 55 | TimeUnit.MILLISECONDS.sleep(500); 56 | System.out.print("Task2.blocker.prodAll() "); 57 | Task2.blocker.prodAll(); 58 | TimeUnit.MILLISECONDS.sleep(500); 59 | System.out.println("\nShutting down"); 60 | exec.shutdownNow(); // Interrupt all tasks 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/OrnamentalGarden.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.*; 6 | 7 | import static util.Print.print; 8 | 9 | class Count { 10 | private int count = 0; 11 | private ThreadLocalRandom rand = ThreadLocalRandom.current(); 12 | 13 | public synchronized int value() { return count; } 14 | 15 | // Counting will fail if remove synchronized 16 | public synchronized int increment() { 17 | int temp = count; 18 | if (rand.nextBoolean()) 19 | Thread.yield(); 20 | return count = ++temp; 21 | } 22 | } 23 | 24 | class Entrance implements Runnable{ 25 | private static Count count = new Count(); 26 | private static volatile boolean cancel = false; 27 | private static List entranceList = 28 | new ArrayList<>(); 29 | private final int id; 30 | private int number = 0; 31 | 32 | public Entrance(int id) { 33 | this.id = id; 34 | entranceList.add(this); 35 | } 36 | 37 | @Override 38 | public void run() { 39 | while(!cancel) { 40 | synchronized (this) { 41 | ++number; 42 | } 43 | print(this + ", total " + count.increment()); 44 | } 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "Entrance " + id + ": number " + getValue(); 50 | } 51 | 52 | public synchronized int getValue() { return number; } 53 | 54 | public static int getTotalCount() { 55 | return count.value(); 56 | } 57 | 58 | public static int sumEntrances() { 59 | int sum = 0; 60 | for (Entrance entrance: entranceList) { 61 | sum += entrance.getValue(); 62 | } 63 | return sum; 64 | } 65 | 66 | public static void cancel() { 67 | cancel = true; 68 | } 69 | } 70 | public class OrnamentalGarden { 71 | public static void main(String[] args) throws InterruptedException { 72 | ExecutorService exec = Executors.newCachedThreadPool(); 73 | for (int i = 0; i < 5; i++) 74 | exec.execute(new Entrance(i)); 75 | 76 | TimeUnit.SECONDS.sleep(3); 77 | Entrance.cancel(); 78 | exec.shutdown(); 79 | 80 | if (!exec.awaitTermination(3, TimeUnit.SECONDS)) 81 | print("Some tasks are not completed"); 82 | 83 | print("Total count " + Entrance.getTotalCount()); 84 | print("Entrance sum " + Entrance.sumEntrances()); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/PriorityBlockingQueueDemo.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.*; 4 | import java.util.*; 5 | import static util.Print.*; 6 | 7 | class PrioritizedTask implements 8 | Runnable, Comparable { 9 | private Random rand = new Random(47); 10 | private static int counter = 0; 11 | private final int id = counter++; 12 | private final int priority; 13 | protected static List sequence = 14 | new ArrayList(); 15 | public PrioritizedTask(int priority) { 16 | this.priority = priority; 17 | sequence.add(this); 18 | } 19 | public int compareTo(PrioritizedTask arg) { 20 | return priority < arg.priority ? 1 : 21 | (priority > arg.priority ? -1 : 0); 22 | } 23 | public void run() { 24 | try { 25 | TimeUnit.MILLISECONDS.sleep(rand.nextInt(250)); 26 | } catch(InterruptedException e) { 27 | // Acceptable way to exit 28 | } 29 | print(this); 30 | } 31 | public String toString() { 32 | return String.format("[%1$-3d]", priority) + 33 | " Task " + id; 34 | } 35 | public String summary() { 36 | return "(" + id + ":" + priority + ")"; 37 | } 38 | public static class EndSentinel extends PrioritizedTask { 39 | private ExecutorService exec; 40 | public EndSentinel(ExecutorService e) { 41 | super(-1); // Lowest priority in this program 42 | exec = e; 43 | } 44 | public void run() { 45 | int count = 0; 46 | for(PrioritizedTask pt : sequence) { 47 | printnb(pt.summary()); 48 | if(++count % 5 == 0) 49 | print(); 50 | } 51 | print(); 52 | print(this + " Calling shutdownNow()"); 53 | exec.shutdownNow(); 54 | } 55 | } 56 | } 57 | 58 | class PrioritizedTaskProducer implements Runnable { 59 | private Random rand = new Random(47); 60 | private Queue queue; 61 | private ExecutorService exec; 62 | public PrioritizedTaskProducer( 63 | Queue q, ExecutorService e) { 64 | queue = q; 65 | exec = e; // Used for EndSentinel 66 | } 67 | public void run() { 68 | // Unbounded queue; never blocks. 69 | // Fill it up fast with random priorities: 70 | for(int i = 0; i < 20; i++) { 71 | queue.add(new PrioritizedTask(rand.nextInt(10))); 72 | Thread.yield(); 73 | } 74 | // Trickle in highest-priority jobs: 75 | try { 76 | for(int i = 0; i < 10; i++) { 77 | TimeUnit.MILLISECONDS.sleep(250); 78 | queue.add(new PrioritizedTask(10)); 79 | } 80 | // Add jobs, lowest priority first: 81 | for(int i = 0; i < 10; i++) 82 | queue.add(new PrioritizedTask(i)); 83 | // A sentinel to stop all the tasks: 84 | queue.add(new PrioritizedTask.EndSentinel(exec)); 85 | } catch(InterruptedException e) { 86 | // Acceptable way to exit 87 | } 88 | print("Finished PrioritizedTaskProducer"); 89 | } 90 | } 91 | 92 | class PrioritizedTaskConsumer implements Runnable { 93 | private PriorityBlockingQueue q; 94 | public PrioritizedTaskConsumer( 95 | PriorityBlockingQueue q) { 96 | this.q = q; 97 | } 98 | public void run() { 99 | try { 100 | while(!Thread.interrupted()) 101 | // Use current thread to run the task: 102 | q.take().run(); 103 | } catch(InterruptedException e) { 104 | // Acceptable way to exit 105 | } 106 | print("Finished PrioritizedTaskConsumer"); 107 | } 108 | } 109 | 110 | public class PriorityBlockingQueueDemo { 111 | public static void main(String[] args) throws Exception { 112 | Random rand = new Random(47); 113 | ExecutorService exec = Executors.newCachedThreadPool(); 114 | PriorityBlockingQueue queue = 115 | new PriorityBlockingQueue(); 116 | exec.execute(new PrioritizedTaskProducer(queue, exec)); 117 | exec.execute(new PrioritizedTaskConsumer(queue)); 118 | } 119 | } -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/ResponsiveUI.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | public class ResponsiveUI extends Thread { 4 | private static volatile double d = 1; 5 | public ResponsiveUI() { 6 | setDaemon(true); 7 | start(); 8 | } 9 | public void run() { 10 | while(true) { 11 | d = d + (Math.PI + Math.E) / d; 12 | } 13 | } 14 | public static void main(String[] args) throws Exception { 15 | //! new UnresponsiveUI(); // Must kill this process 16 | new ResponsiveUI(); 17 | System.in.read(); 18 | System.out.println(d); // Shows progress 19 | } 20 | } 21 | 22 | class UnresponsiveUI { 23 | private volatile double d = 1; 24 | public UnresponsiveUI() throws Exception { 25 | while(d > 0) 26 | d = d + (Math.PI + Math.E) / d; 27 | System.in.read(); // Never gets here 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/Restaurant.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import static util.Print.print; 9 | import static util.Print.printnb; 10 | 11 | class Meal { 12 | private final int orderNum; 13 | public Meal(int orderNum) { 14 | this.orderNum = orderNum; 15 | } 16 | public String toString() { 17 | return "Meal " + this.orderNum; 18 | } 19 | } 20 | 21 | class WaitPerson implements Runnable { 22 | private Restaurant restaurant; 23 | public WaitPerson(Restaurant restaurant) { 24 | this.restaurant = restaurant; 25 | } 26 | 27 | @Override 28 | public void run() { 29 | try { 30 | while (!Thread.interrupted()) { 31 | synchronized (this) { 32 | while(restaurant.meal == null) 33 | wait(); 34 | } 35 | print(" WaitPerson got " + restaurant.meal); 36 | synchronized (restaurant.chef) { 37 | restaurant.meal = null; 38 | restaurant.chef.notifyAll(); 39 | } 40 | } 41 | } catch (InterruptedException e) { 42 | print("WaitPerson exiting via interrupt"); 43 | } 44 | } 45 | } 46 | class Chef implements Runnable { 47 | private Restaurant restaurant; 48 | private int count = 0; 49 | public Chef(Restaurant restaurant) { 50 | this.restaurant = restaurant; 51 | } 52 | 53 | @Override 54 | public void run() { 55 | try { 56 | while(!Thread.interrupted()) { 57 | synchronized (this) { 58 | while(restaurant.meal != null) 59 | wait(); 60 | } 61 | if (count++ == 10) { 62 | print("Out of food, closing"); 63 | restaurant.exec.shutdownNow(); 64 | } 65 | printnb("Cooking order " + count + " "); 66 | TimeUnit.MILLISECONDS.sleep(100); 67 | synchronized (restaurant.waitPerson) { 68 | restaurant.meal = new Meal(count); 69 | restaurant.waitPerson.notifyAll(); 70 | } 71 | } 72 | } catch (InterruptedException e) { 73 | print("WaitPerson exiting via interrupt"); 74 | } 75 | } 76 | } 77 | 78 | public class Restaurant { 79 | Meal meal ; 80 | WaitPerson waitPerson = new WaitPerson(this); 81 | Chef chef = new Chef(this); 82 | ExecutorService exec = Executors.newCachedThreadPool(); 83 | 84 | public Restaurant() { 85 | exec.execute(chef); 86 | exec.execute(waitPerson); 87 | } 88 | 89 | public static void main(String[] args) { 90 | new Restaurant(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/SerialNumberChecker.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.Arrays; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import static util.Print.print; 9 | 10 | class CircularSet { 11 | private int[] array; 12 | private int size; 13 | private int index = 0; 14 | 15 | public CircularSet(int size) { 16 | this.size = size; 17 | array = new int[size]; 18 | 19 | Arrays.fill(array, -1); 20 | } 21 | 22 | public synchronized void add(int val) { 23 | array[index++] = val; 24 | index %= size; 25 | } 26 | 27 | public synchronized boolean contains(int val) { 28 | for (int i = 0; i < size; i++) { 29 | if (array[i] == val) 30 | return true; 31 | } 32 | 33 | return false; 34 | } 35 | } 36 | public class SerialNumberChecker { 37 | private static final int SIZE = 10; 38 | private static CircularSet serials = new CircularSet(1000); 39 | private static ExecutorService exec = Executors.newCachedThreadPool(); 40 | 41 | static class SerialChecker implements Runnable { 42 | @Override 43 | public void run() { 44 | while (true) { 45 | int serialNumber = SerialNumberGenerator.nextSerialNumber(); 46 | if (serials.contains(serialNumber)) { 47 | print("Duplicate " + serialNumber); 48 | System.exit(0); 49 | } 50 | serials.add(serialNumber); 51 | } 52 | 53 | } 54 | } 55 | 56 | public static void main(String[] args) throws InterruptedException { 57 | for (int i = 0; i < SIZE; i++) { 58 | exec.execute(new SerialChecker()); 59 | } 60 | 61 | if (args.length > 0) { 62 | TimeUnit.SECONDS.sleep(Integer.valueOf(args[0])); 63 | print("No duplicate found"); 64 | System.exit(0); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/SerialNumberGenerator.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | public class SerialNumberGenerator { 4 | private static volatile int serialNumber = 0; 5 | public static int nextSerialNumber() { 6 | return serialNumber++; // Not thread safe 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/SettingDefaultHandler.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | 7 | public class SettingDefaultHandler { 8 | public static void main(String[] args) { 9 | Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); 10 | ExecutorService exec = Executors.newCachedThreadPool(); 11 | exec.execute(new ExceptionThread()); 12 | } 13 | } 14 | //caught java.lang.RuntimeException -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/SimpleDaemons.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import static util.Print.print; 6 | 7 | public class SimpleDaemons implements Runnable { 8 | public void run() { 9 | try { 10 | while(true) { 11 | TimeUnit.MILLISECONDS.sleep(100); 12 | print(Thread.currentThread() + " " + this); 13 | } 14 | } catch(InterruptedException e) { 15 | print("sleep() interrupted"); 16 | } 17 | } 18 | public static void main(String[] args) throws Exception { 19 | for(int i = 0; i < 10; i++) { 20 | Thread daemon = new Thread(new SimpleDaemons()); 21 | daemon.setDaemon(true); // Must call before start() 22 | daemon.start(); 23 | } 24 | print("All daemons started"); 25 | TimeUnit.MILLISECONDS.sleep(175); 26 | } 27 | } /* Output: (Sample) 28 | All daemons started 29 | Thread[Thread-0,5,main] SimpleDaemons@530daa 30 | Thread[Thread-1,5,main] SimpleDaemons@a62fc3 31 | Thread[Thread-2,5,main] SimpleDaemons@89ae9e 32 | Thread[Thread-3,5,main] SimpleDaemons@1270b73 33 | Thread[Thread-4,5,main] SimpleDaemons@60aeb0 34 | Thread[Thread-5,5,main] SimpleDaemons@16caf43 35 | Thread[Thread-6,5,main] SimpleDaemons@66848c 36 | Thread[Thread-7,5,main] SimpleDaemons@8813f2 37 | Thread[Thread-8,5,main] SimpleDaemons@1d58aae 38 | Thread[Thread-9,5,main] SimpleDaemons@83cc67 39 | ... 40 | */ 41 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/SingleThreadPool.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | public class SingleThreadPool { 7 | public static void main(String[] args) { 8 | ExecutorService executor = Executors.newSingleThreadExecutor(); 9 | for (int i = 0; i < 5; i++) { 10 | executor.execute(new LiftOff()); 11 | } 12 | executor.shutdown(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/SynchronizedEvenGenerator.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | public class SynchronizedEvenGenerator extends IntGenerator { 4 | // volatile doesn't make any difference 5 | private /* volatile */ int currentEvenValue = 0; 6 | @Override 7 | public synchronized int next() { 8 | ++currentEvenValue; 9 | Thread.yield(); 10 | ++currentEvenValue; 11 | 12 | return currentEvenValue; 13 | } 14 | 15 | public static void main(String[] args) { 16 | EvenChecker.test(new SynchronizedEvenGenerator(), 10); 17 | } 18 | }/* Output: 19 | infinite loop.... 20 | */ 21 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/TestCyclicBarrier.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.Random; 4 | import java.util.concurrent.BrokenBarrierException; 5 | import java.util.concurrent.CyclicBarrier; 6 | 7 | public class TestCyclicBarrier { 8 | private static final int THREAD_NUMBER = 5; 9 | private static final Random RANDOM = new Random(); 10 | public static void main(String[] args) { 11 | CyclicBarrier barrier = new CyclicBarrier(THREAD_NUMBER, new Runnable() { 12 | public void run() { 13 | System.out.println(Thread.currentThread().getId() + ":我宣布,所有小伙伴写入数据完毕"); 14 | } 15 | }); 16 | for (int i = 0; i < THREAD_NUMBER; i++) { 17 | Thread t = new Thread(new Worker(barrier)); 18 | t.start(); 19 | } 20 | } 21 | static class Worker implements Runnable { 22 | private CyclicBarrier barrier; 23 | public Worker(CyclicBarrier barrier) { 24 | this.barrier = barrier; 25 | } 26 | public void run() { 27 | int time = RANDOM.nextInt(1000); 28 | System.out.println(Thread.currentThread().getId() + ":我需要" + time + "毫秒时间写入数据."); 29 | try { 30 | Thread.sleep(time); 31 | } catch (InterruptedException e) { 32 | e.printStackTrace(); 33 | } 34 | System.out.println(Thread.currentThread().getId() + ":写入数据完毕,等待其他小伙伴..."); 35 | try { 36 | barrier.await(); // 等待所有线程都调用过此函数才能进行后续动作 37 | } catch (InterruptedException e) { 38 | e.printStackTrace(); 39 | } catch (BrokenBarrierException e) { 40 | e.printStackTrace(); 41 | } 42 | System.out.println(Thread.currentThread().getId() + ":所有线程都写入数据完毕,继续干活..."); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/TestingBlockingQueues.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.*; 4 | 5 | import static util.Print.print; 6 | 7 | class LiftOffRunner implements Runnable { 8 | private BlockingQueue rockets; 9 | public LiftOffRunner(BlockingQueue queue) { 10 | this.rockets = queue; 11 | } 12 | 13 | public void add(LiftOff lo) { 14 | try { 15 | rockets.put(lo); 16 | } catch (InterruptedException e) { 17 | print("put was interrupted"); 18 | } 19 | } 20 | 21 | @Override 22 | public void run() { 23 | print("Runner start running"); 24 | try { 25 | while (!Thread.interrupted()) { 26 | LiftOff rocket = rockets.take(); 27 | rocket.run(); 28 | } 29 | } catch (InterruptedException e) { 30 | print("interruption during take()"); 31 | } 32 | print("Exiting LiftOffRunner run()"); 33 | } 34 | } 35 | public class TestingBlockingQueues { 36 | static void test(String msg, BlockingQueue queue) throws InterruptedException { 37 | print(msg); 38 | LiftOffRunner runner = new LiftOffRunner(queue); 39 | Thread t = new Thread(runner); 40 | t.start(); 41 | 42 | TimeUnit.SECONDS.sleep(2); 43 | for (int i = 0; i < 10; i++) { 44 | runner.add(new LiftOff(5)); 45 | } 46 | 47 | TimeUnit.SECONDS.sleep(2); 48 | print("Interrupting " + msg); 49 | t.interrupt(); 50 | print("Finish testing " + msg); 51 | } 52 | 53 | public static void main(String[] args) throws InterruptedException { 54 | test("LinkedBlockingQueue", // Unlimited size 55 | new LinkedBlockingQueue()); 56 | TimeUnit.SECONDS.sleep(2); 57 | test("ArrayBlockingQueue", // Fixed size 58 | new ArrayBlockingQueue(3)); 59 | TimeUnit.SECONDS.sleep(2); 60 | test("SynchronousQueue", // Size of 1 61 | new SynchronousQueue()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/ThreadVariations.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import static util.Print.print; 6 | 7 | // Using a named inner class: 8 | class InnerThread1 { 9 | private int countDown = 5; 10 | private Inner inner; 11 | private class Inner extends Thread { 12 | Inner(String name) { 13 | super(name); 14 | start(); 15 | } 16 | public void run() { 17 | try { 18 | while(true) { 19 | print(this); 20 | if(--countDown == 0) return; 21 | sleep(10); 22 | } 23 | } catch(InterruptedException e) { 24 | print("interrupted"); 25 | } 26 | } 27 | public String toString() { 28 | return getName() + ": " + countDown; 29 | } 30 | } 31 | public InnerThread1(String name) { 32 | inner = new Inner(name); 33 | } 34 | } 35 | 36 | // Using an anonymous inner class: 37 | class InnerThread2 { 38 | private int countDown = 5; 39 | private Thread t; 40 | public InnerThread2(String name) { 41 | t = new Thread(name) { 42 | public void run() { 43 | try { 44 | while(true) { 45 | print(this); 46 | if(--countDown == 0) return; 47 | sleep(10); 48 | } 49 | } catch(InterruptedException e) { 50 | print("sleep() interrupted"); 51 | } 52 | } 53 | public String toString() { 54 | return getName() + ": " + countDown; 55 | } 56 | }; 57 | t.start(); 58 | } 59 | } 60 | 61 | // Using a named Runnable implementation: 62 | class InnerRunnable1 { 63 | private int countDown = 5; 64 | private Inner inner; 65 | private class Inner implements Runnable { 66 | Thread t; 67 | Inner(String name) { 68 | t = new Thread(this, name); 69 | t.start(); 70 | } 71 | public void run() { 72 | try { 73 | while(true) { 74 | print(this); 75 | if(--countDown == 0) return; 76 | TimeUnit.MILLISECONDS.sleep(10); 77 | } 78 | } catch(InterruptedException e) { 79 | print("sleep() interrupted"); 80 | } 81 | } 82 | public String toString() { 83 | return t.getName() + ": " + countDown; 84 | } 85 | } 86 | public InnerRunnable1(String name) { 87 | inner = new Inner(name); 88 | } 89 | } 90 | 91 | // Using an anonymous Runnable implementation: 92 | class InnerRunnable2 { 93 | private int countDown = 5; 94 | private Thread t; 95 | public InnerRunnable2(String name) { 96 | t = new Thread(new Runnable() { 97 | public void run() { 98 | try { 99 | while(true) { 100 | print(this); 101 | if(--countDown == 0) return; 102 | TimeUnit.MILLISECONDS.sleep(10); 103 | } 104 | } catch(InterruptedException e) { 105 | print("sleep() interrupted"); 106 | } 107 | } 108 | public String toString() { 109 | return Thread.currentThread().getName() + 110 | ": " + countDown; 111 | } 112 | }, name); 113 | t.start(); 114 | } 115 | } 116 | 117 | // A separate method to run some code as a task: 118 | class ThreadMethod { 119 | private int countDown = 5; 120 | private Thread t; 121 | private String name; 122 | public ThreadMethod(String name) { this.name = name; } 123 | public void runTask() { 124 | if(t == null) { 125 | t = new Thread(name) { 126 | public void run() { 127 | try { 128 | while(true) { 129 | print(this); 130 | if(--countDown == 0) return; 131 | sleep(10); 132 | } 133 | } catch(InterruptedException e) { 134 | print("sleep() interrupted"); 135 | } 136 | } 137 | public String toString() { 138 | return getName() + ": " + countDown; 139 | } 140 | }; 141 | t.start(); 142 | } 143 | } 144 | } 145 | 146 | public class ThreadVariations { 147 | public static void main(String[] args) { 148 | new InnerThread1("InnerThread1"); 149 | new InnerThread2("InnerThread2"); 150 | new InnerRunnable1("InnerRunnable1"); 151 | new InnerRunnable2("InnerRunnable2"); 152 | new ThreadMethod("ThreadMethod").runTask(); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/ToastOMatic.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.Random; 4 | import java.util.concurrent.*; 5 | 6 | import static util.Print.print; 7 | 8 | class Toast { 9 | public enum Status { DRY, BUTTERED, JAMMED } 10 | private Status status = Status.DRY; 11 | private final int id; 12 | public Toast(int idn) { id = idn; } 13 | public void butter() { status = Status.BUTTERED; } 14 | public void jam() { status = Status.JAMMED; } 15 | public Status getStatus() { return status; } 16 | public int getId() { return id; } 17 | public String toString() { 18 | return "Toast " + id + ": " + status; 19 | } 20 | } 21 | 22 | class ToastQueue extends LinkedBlockingQueue {} 23 | 24 | class Toaster implements Runnable { 25 | private ToastQueue toastQueue; 26 | private int count = 0; 27 | private Random rand = new Random(47); 28 | public Toaster(ToastQueue tq) { toastQueue = tq; } 29 | public void run() { 30 | try { 31 | while(!Thread.interrupted()) { 32 | TimeUnit.MILLISECONDS.sleep( 33 | 100 + rand.nextInt(500)); 34 | // Make toast 35 | Toast t = new Toast(count++); 36 | print(t); 37 | // Insert into queue 38 | toastQueue.put(t); 39 | } 40 | } catch(InterruptedException e) { 41 | print("Toaster interrupted"); 42 | } 43 | print("Toaster off"); 44 | } 45 | } 46 | 47 | // Apply butter to toast: 48 | class Butterer implements Runnable { 49 | private ToastQueue dryQueue, butteredQueue; 50 | public Butterer(ToastQueue dry, ToastQueue buttered) { 51 | dryQueue = dry; 52 | butteredQueue = buttered; 53 | } 54 | public void run() { 55 | try { 56 | while(!Thread.interrupted()) { 57 | // Blocks until next piece of toast is available: 58 | Toast t = dryQueue.take(); 59 | t.butter(); 60 | print(t); 61 | butteredQueue.put(t); 62 | } 63 | } catch(InterruptedException e) { 64 | print("Butterer interrupted"); 65 | } 66 | print("Butterer off"); 67 | } 68 | } 69 | 70 | // Apply jam to buttered toast: 71 | class Jammer implements Runnable { 72 | private ToastQueue butteredQueue, finishedQueue; 73 | public Jammer(ToastQueue buttered, ToastQueue finished) { 74 | butteredQueue = buttered; 75 | finishedQueue = finished; 76 | } 77 | public void run() { 78 | try { 79 | while(!Thread.interrupted()) { 80 | // Blocks until next piece of toast is available: 81 | Toast t = butteredQueue.take(); 82 | t.jam(); 83 | print(t); 84 | finishedQueue.put(t); 85 | } 86 | } catch(InterruptedException e) { 87 | print("Jammer interrupted"); 88 | } 89 | print("Jammer off"); 90 | } 91 | } 92 | 93 | // Consume the toast: 94 | class Eater implements Runnable { 95 | private ToastQueue finishedQueue; 96 | private int counter = 0; 97 | public Eater(ToastQueue finished) { 98 | finishedQueue = finished; 99 | } 100 | public void run() { 101 | try { 102 | while(!Thread.interrupted()) { 103 | // Blocks until next piece of toast is available: 104 | Toast t = finishedQueue.take(); 105 | // Verify that the toast is coming in order, 106 | // and that all pieces are getting jammed: 107 | if(t.getId() != counter++ || 108 | t.getStatus() != Toast.Status.JAMMED) { 109 | print(">>>> Error: " + t); 110 | System.exit(1); 111 | } else 112 | print("Chomp! " + t); 113 | } 114 | } catch(InterruptedException e) { 115 | print("Eater interrupted"); 116 | } 117 | print("Eater off"); 118 | } 119 | } 120 | 121 | public class ToastOMatic { 122 | public static void main(String[] args) throws Exception { 123 | ToastQueue dryQueue = new ToastQueue(), 124 | butteredQueue = new ToastQueue(), 125 | finishedQueue = new ToastQueue(); 126 | ExecutorService exec = Executors.newCachedThreadPool(); 127 | exec.execute(new Toaster(dryQueue)); 128 | exec.execute(new Butterer(dryQueue, butteredQueue)); 129 | exec.execute(new Jammer(butteredQueue, finishedQueue)); 130 | exec.execute(new Eater(finishedQueue)); 131 | TimeUnit.SECONDS.sleep(3); 132 | exec.shutdownNow(); 133 | } 134 | }/* Output 135 | Toast 0: DRY 136 | Toast 0: BUTTERED 137 | Toast 0: JAMMED 138 | Chomp! Toast 0: JAMMED 139 | Toast 1: DRY 140 | Toast 1: BUTTERED 141 | Toast 1: JAMMED 142 | Chomp! Toast 1: JAMMED 143 | Toast 2: DRY 144 | Toast 2: BUTTERED 145 | Toast 2: JAMMED 146 | Chomp! Toast 2: JAMMED 147 | Toast 3: DRY 148 | Toast 3: BUTTERED 149 | Toast 3: JAMMED 150 | Chomp! Toast 3: JAMMED 151 | Toast 4: DRY 152 | Toast 4: BUTTERED 153 | Toast 4: JAMMED 154 | Chomp! Toast 4: JAMMED 155 | Toast 5: DRY 156 | Toast 5: BUTTERED 157 | Toast 5: JAMMED 158 | Chomp! Toast 5: JAMMED 159 | Toast 6: DRY 160 | Toast 6: BUTTERED 161 | Toast 6: JAMMED 162 | Chomp! Toast 6: JAMMED 163 | Eater interrupted 164 | Eater off 165 | Jammer interrupted 166 | Jammer off 167 | Butterer interrupted 168 | Butterer off 169 | Toaster interrupted 170 | Toaster off 171 | */ -------------------------------------------------------------------------------- /src/main/java/ch21concurrency/WaxOMatic.java: -------------------------------------------------------------------------------- 1 | package ch21concurrency; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import static util.Print.print; 9 | 10 | class Car { 11 | private boolean waxed = false; 12 | 13 | public synchronized void waxed() { 14 | waxed = true; 15 | notifyAll(); 16 | } 17 | 18 | public synchronized void buffed() { 19 | waxed = false; 20 | notifyAll(); 21 | } 22 | 23 | public synchronized void waitForWaxing() throws InterruptedException { 24 | while(waxed == false) { 25 | wait(); 26 | } 27 | } 28 | 29 | public synchronized void waitForBuffing() throws InterruptedException { 30 | while(waxed == true) { 31 | wait(); 32 | } 33 | } 34 | } 35 | 36 | class WaxOn implements Runnable { 37 | private Car car; 38 | 39 | public WaxOn(Car car) { 40 | this.car = car; 41 | } 42 | 43 | @Override 44 | public void run() { 45 | // try { 46 | while (!Thread.interrupted()) { 47 | try { 48 | print("Wax On!"); 49 | TimeUnit.SECONDS.sleep(1); 50 | car.waxed(); 51 | car.waitForBuffing(); 52 | } catch (InterruptedException e) { 53 | print("Received interruption"); 54 | } 55 | } 56 | // } catch (InterruptedException e) { 57 | // print("Exiting via Interrupt"); 58 | // } 59 | print("Ending Wax On task"); 60 | } 61 | } 62 | 63 | class WaxOff implements Runnable { 64 | private Car car; 65 | public WaxOff(Car car) { 66 | this.car = car; 67 | } 68 | 69 | @Override 70 | public void run() { 71 | //try { 72 | while(!Thread.interrupted()) { 73 | try { 74 | car.waitForWaxing(); 75 | print("Wax Off!"); 76 | TimeUnit.SECONDS.sleep(1); 77 | car.buffed(); 78 | } catch (InterruptedException e) { 79 | print("Received interruption"); 80 | } 81 | } 82 | // } catch (InterruptedException e) { 83 | // print("Exiting via interrupt"); 84 | // } 85 | print("Ending Wax Off task"); 86 | } 87 | } 88 | public class WaxOMatic { 89 | public static void main(String[] args) throws InterruptedException { 90 | ExecutorService exec = Executors.newCachedThreadPool(); 91 | Car car = new Car(); 92 | 93 | exec.execute(new WaxOff(car)); 94 | exec.execute(new WaxOn(car)); 95 | 96 | TimeUnit.SECONDS.sleep(5); 97 | exec.shutdownNow();// 如果任务ignore interruption, shutdownNow()无法停止线程 98 | //exec.shutdown(); // shutdown并不会关闭已经运行的线程,只会停止创建新线程 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/main_for_test/MainForTest.java: -------------------------------------------------------------------------------- 1 | package main_for_test; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * Created by DengWenzhe on 3/9/17. 7 | */ 8 | public class MainForTest { 9 | 10 | public static void main(String[] args) { 11 | int[][] a = { 12 | {1, 2, 3}, 13 | {4, 5, 6, 7} 14 | }; 15 | 16 | System.out.println(Arrays.deepToString(a)); 17 | 18 | Integer[][][] b = new Integer[2][3][]; 19 | System.out.println(Arrays.deepToString(b)); 20 | 21 | List> nestedList = new ArrayList<>(); 22 | List list = Arrays.asList(1, 2, 3); 23 | nestedList.add(list); 24 | 25 | System.out.println(nestedList); 26 | 27 | nestedList.add(list.subList(0, 2)); 28 | 29 | System.out.println(nestedList); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/util/CollectionData.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | /** 4 | * Created by DengWenzhe on 3/18/17. 5 | */ 6 | import java.util.ArrayList; 7 | 8 | public class CollectionData extends ArrayList { 9 | public CollectionData(Generator gen, int quantity) { 10 | for (int i = 0; i < quantity; i++) 11 | add(gen.next()); 12 | } 13 | 14 | // A generic convenience method: 15 | public static CollectionData list(Generator gen, int quantity) { 16 | return new CollectionData(gen, quantity); 17 | } 18 | } 19 | 20 | class CollectionDataTest { 21 | public static void main(String[] args) { 22 | ArrayList list = new CollectionData(new RandomGenerator.String(9), 10); 23 | System.out.println(list); 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/util/CountingGenerator.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | public class CountingGenerator { 4 | public static class 5 | Boolean implements Generator { 6 | private boolean value = false; 7 | public java.lang.Boolean next() { 8 | value = !value; // Just flips back and forth 9 | return value; 10 | } 11 | } 12 | public static class 13 | Byte implements Generator { 14 | private byte value = 0; 15 | public java.lang.Byte next() { return value++; } 16 | } 17 | static char[] chars = ("abcdefghijklmnopqrstuvwxyz" + 18 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray(); 19 | public static class 20 | Character implements Generator { 21 | int index = -1; 22 | public java.lang.Character next() { 23 | index = (index + 1) % chars.length; 24 | return chars[index]; 25 | } 26 | } 27 | public static class 28 | String implements Generator { 29 | private int length = 7; 30 | Generator cg = new Character(); 31 | public String() {} 32 | public String(int length) { this.length = length; } 33 | public java.lang.String next() { 34 | char[] buf = new char[length]; 35 | for(int i = 0; i < length; i++) 36 | buf[i] = cg.next(); 37 | return new java.lang.String(buf); 38 | } 39 | } 40 | public static class 41 | Short implements Generator { 42 | private short value = 0; 43 | public java.lang.Short next() { return value++; } 44 | } 45 | public static class 46 | Integer implements Generator { 47 | private int value = 0; 48 | public java.lang.Integer next() { return value++; } 49 | } 50 | public static class 51 | Long implements Generator { 52 | private long value = 0; 53 | public java.lang.Long next() { return value++; } 54 | } 55 | public static class 56 | Float implements Generator { 57 | private float value = 0; 58 | public java.lang.Float next() { 59 | float result = value; 60 | value += 1.0; 61 | return result; 62 | } 63 | } 64 | public static class 65 | Double implements Generator { 66 | private double value = 0.0; 67 | public java.lang.Double next() { 68 | double result = value; 69 | value += 1.0; 70 | return result; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/util/CountingIntegerList.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.util.AbstractList; 4 | 5 | public class CountingIntegerList 6 | extends AbstractList { 7 | private int size; 8 | public CountingIntegerList(int size) { 9 | this.size = size < 0 ? 0 : size; 10 | } 11 | public Integer get(int index) { 12 | return Integer.valueOf(index); 13 | } 14 | public int size() { return size; } 15 | public static void main(String[] args) { 16 | System.out.println(new CountingIntegerList(30)); 17 | } 18 | } /* Output: 19 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29] 20 | */ -------------------------------------------------------------------------------- /src/main/java/util/CountingMapData.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.util.*; 4 | 5 | public class CountingMapData 6 | extends AbstractMap { 7 | private int size; 8 | private static String[] chars = 9 | "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z" 10 | .split(" "); 11 | public CountingMapData(int size) { 12 | if(size < 0) this.size = 0; 13 | this.size = size; 14 | } 15 | private static class Entry 16 | implements Map.Entry { 17 | int index; 18 | Entry(int index) { this.index = index; } 19 | public boolean equals(Object o) { 20 | return Integer.valueOf(index).equals(o); 21 | } 22 | public Integer getKey() { return index; } 23 | public String getValue() { 24 | return 25 | chars[index % chars.length] + 26 | Integer.toString(index / chars.length); 27 | } 28 | public String setValue(String value) { 29 | throw new UnsupportedOperationException(); 30 | } 31 | public int hashCode() { 32 | return Integer.valueOf(index).hashCode(); 33 | } 34 | } 35 | public Set> entrySet() { 36 | // LinkedHashSet retains initialization order: 37 | Set> entries = 38 | new LinkedHashSet>(); 39 | for(int i = 0; i < size; i++) 40 | entries.add(new Entry(i)); 41 | return entries; 42 | } 43 | public static void main(String[] args) { 44 | System.out.println(new CountingMapData(60)); 45 | } 46 | } /* Output: 47 | {0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0, 9=J0, 10=K0, 11=L0, 12=M0, 13=N0, 14=O0, 15=P0, 16=Q0, 17=R0, 18=S0, 19=T0, 20=U0, 21=V0, 22=W0, 23=X0, 24=Y0, 25=Z0, 26=A1, 27=B1, 28=C1, 29=D1, 30=E1, 31=F1, 32=G1, 33=H1, 34=I1, 35=J1, 36=K1, 37=L1, 38=M1, 39=N1, 40=O1, 41=P1, 42=Q1, 43=R1, 44=S1, 45=T1, 46=U1, 47=V1, 48=W1, 49=X1, 50=Y1, 51=Z1, 52=A2, 53=B2, 54=C2, 55=D2, 56=E2, 57=F2, 58=G2, 59=H2} 48 | */ -------------------------------------------------------------------------------- /src/main/java/util/Countries.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | /** 4 | * Created by DengWenzhe on 3/19/17. 5 | */ 6 | import java.util.*; 7 | 8 | 9 | public class Countries { 10 | public static final String[][] DATA = { 11 | // Africa 12 | {"ALGERIA", "Algiers"}, 13 | {"ANGOLA", "Luanda"}, 14 | {"BENIN", "Porto-Novo"}, 15 | {"BOTSWANA", "Gaberone"}, 16 | {"BURKINA FASO", "Ouagadougou"}, 17 | {"BURUNDI", "Bujumbura"}, 18 | {"CAMEROON", "Yaounde"}, 19 | {"CAPE VERDE", "Praia"}, 20 | {"CENTRAL AFRICAN REPUBLIC", "Bangui"}, 21 | {"CHAD", "N'djamena"}, 22 | {"COMOROS", "Moroni"}, 23 | {"CONGO", "Brazzaville"}, 24 | {"DJIBOUTI", "Dijibouti"}, 25 | {"EGYPT", "Cairo"}, 26 | {"EQUATORIAL GUINEA", "Malabo"}, 27 | {"ERITREA", "Asmara"}, 28 | {"ETHIOPIA", "Addis Ababa"}, 29 | {"GABON", "Libreville"}, 30 | {"THE GAMBIA", "Banjul"}, 31 | {"GHANA", "Accra"}, 32 | {"GUINEA", "Conakry"}, 33 | {"BISSAU", "Bissau"}, 34 | {"COTE D'IVOIR (IVORY COAST)", "Yamoussoukro"}, 35 | {"KENYA", "Nairobi"}, 36 | {"LESOTHO", "Maseru"}, 37 | {"LIBERIA", "Monrovia"}, 38 | {"LIBYA", "Tripoli"}, 39 | {"MADAGASCAR", "Antananarivo"}, 40 | {"MALAWI", "Lilongwe"}, 41 | {"MALI", "Bamako"}, 42 | {"MAURITANIA", "Nouakchott"}, 43 | {"MAURITIUS", "Port Louis"}, 44 | {"MOROCCO", "Rabat"}, 45 | {"MOZAMBIQUE", "Maputo"}, 46 | {"NAMIBIA", "Windhoek"}, 47 | {"NIGER", "Niamey"}, 48 | {"NIGERIA", "Abuja"}, 49 | {"RWANDA", "Kigali"}, 50 | {"SAO TOME E PRINCIPE", "Sao Tome"}, 51 | {"SENEGAL", "Dakar"}, 52 | {"SEYCHELLES", "Victoria"}, 53 | {"SIERRA LEONE", "Freetown"}, 54 | {"SOMALIA", "Mogadishu"}, 55 | {"SOUTH AFRICA", "Pretoria/Cape Town"}, 56 | {"SUDAN", "Khartoum"}, 57 | {"SWAZILAND", "Mbabane"}, 58 | {"TANZANIA", "Dodoma"}, 59 | {"TOGO", "Lome"}, 60 | {"TUNISIA", "Tunis"}, 61 | {"UGANDA", "Kampala"}, 62 | {"DEMOCRATIC REPUBLIC OF THE CONGO (ZAIRE)", "Kinshasa"}, 63 | {"ZAMBIA", "Lusaka"}, 64 | {"ZIMBABWE", "Harare"}, 65 | // Asia 66 | {"AFGHANISTAN", "Kabul"}, 67 | {"BAHRAIN", "Manama"}, 68 | {"BANGLADESH", "Dhaka"}, 69 | {"BHUTAN", "Thimphu"}, 70 | {"BRUNEI", "Bandar Seri Begawan"}, 71 | {"CAMBODIA", "Phnom Penh"}, 72 | {"CHINA", "Beijing"}, 73 | {"CYPRUS", "Nicosia"}, 74 | {"INDIA", "New Delhi"}, 75 | {"INDONESIA", "Jakarta"}, 76 | {"IRAN", "Tehran"}, 77 | {"IRAQ", "Baghdad"}, 78 | {"ISRAEL", "Jerusalem"}, 79 | {"JAPAN", "Tokyo"}, 80 | {"JORDAN", "Amman"}, 81 | {"KUWAIT", "Kuwait City"}, 82 | {"LAOS", "Vientiane"}, 83 | {"LEBANON", "Beirut"}, 84 | {"MALAYSIA", "Kuala Lumpur"}, 85 | {"THE MALDIVES", "Male"}, 86 | {"MONGOLIA", "Ulan Bator"}, 87 | {"MYANMAR (BURMA)", "Rangoon"}, 88 | {"NEPAL", "Katmandu"}, 89 | {"NORTH KOREA", "P'yongyang"}, 90 | {"OMAN", "Muscat"}, 91 | {"PAKISTAN", "Islamabad"}, 92 | {"PHILIPPINES", "Manila"}, 93 | {"QATAR", "Doha"}, 94 | {"SAUDI ARABIA", "Riyadh"}, 95 | {"SINGAPORE", "Singapore"}, 96 | {"SOUTH KOREA", "Seoul"}, 97 | {"SRI LANKA", "Colombo"}, 98 | {"SYRIA", "Damascus"}, 99 | {"TAIWAN (REPUBLIC OF CHINA)", "Taipei"}, 100 | {"THAILAND", "Bangkok"}, 101 | {"TURKEY", "Ankara"}, 102 | {"UNITED ARAB EMIRATES", "Abu Dhabi"}, 103 | {"VIETNAM", "Hanoi"}, 104 | {"YEMEN", "Sana'a"}, 105 | // Australia and Oceania 106 | {"AUSTRALIA", "Canberra"}, 107 | {"FIJI", "Suva"}, 108 | {"KIRIBATI", "Bairiki"}, 109 | {"MARSHALL ISLANDS", "Dalap-Uliga-Darrit"}, 110 | {"MICRONESIA", "Palikir"}, 111 | {"NAURU", "Yaren"}, 112 | {"NEW ZEALAND", "Wellington"}, 113 | {"PALAU", "Koror"}, 114 | {"PAPUA NEW GUINEA", "Port Moresby"}, 115 | {"SOLOMON ISLANDS", "Honaira"}, 116 | {"TONGA", "Nuku'alofa"}, 117 | {"TUVALU", "Fongafale"}, 118 | {"VANUATU", "< Port-Vila"}, 119 | {"WESTERN SAMOA", "Apia"}, 120 | // Eastern Europe and former USSR 121 | {"ARMENIA", "Yerevan"}, 122 | {"AZERBAIJAN", "Baku"}, 123 | {"BELARUS (BYELORUSSIA)", "Minsk"}, 124 | {"BULGARIA", "Sofia"}, 125 | {"GEORGIA", "Tbilisi"}, 126 | {"KAZAKSTAN", "Almaty"}, 127 | {"KYRGYZSTAN", "Alma-Ata"}, 128 | {"MOLDOVA", "Chisinau"}, 129 | {"RUSSIA", "Moscow"}, 130 | {"TAJIKISTAN", "Dushanbe"}, 131 | {"TURKMENISTAN", "Ashkabad"}, 132 | {"UKRAINE", "Kyiv"}, 133 | {"UZBEKISTAN", "Tashkent"}, 134 | // Europe 135 | {"ALBANIA", "Tirana"}, {"ANDORRA", "Andorra la Vella"}, 136 | {"AUSTRIA", "Vienna"}, {"BELGIUM", "Brussels"}, 137 | {"BOSNIA", "-"}, 138 | {"HERZEGOVINA", "Sarajevo"}, 139 | {"CROATIA", "Zagreb"}, 140 | {"CZECH REPUBLIC", "Prague"}, 141 | {"DENMARK", "Copenhagen"}, 142 | {"ESTONIA", "Tallinn"}, 143 | {"FINLAND", "Helsinki"}, 144 | {"FRANCE", "Paris"}, 145 | {"GERMANY", "Berlin"}, 146 | {"GREECE", "Athens"}, 147 | {"HUNGARY", "Budapest"}, 148 | {"ICELAND", "Reykjavik"}, 149 | {"IRELAND", "Dublin"}, 150 | {"ITALY", "Rome"}, 151 | {"LATVIA", "Riga"}, 152 | {"LIECHTENSTEIN", "Vaduz"}, 153 | {"LITHUANIA", "Vilnius"}, 154 | {"LUXEMBOURG", "Luxembourg"}, 155 | {"MACEDONIA", "Skopje"}, 156 | {"MALTA", "Valletta"}, 157 | {"MONACO", "Monaco"}, 158 | {"MONTENEGRO", "Podgorica"}, 159 | {"THE NETHERLANDS", "Amsterdam"}, 160 | {"NORWAY", "Oslo"}, 161 | {"POLAND", "Warsaw"}, 162 | {"PORTUGAL", "Lisbon"}, 163 | {"ROMANIA", "Bucharest"}, 164 | {"SAN MARINO", "San Marino"}, 165 | {"SERBIA", "Belgrade"}, 166 | {"SLOVAKIA", "Bratislava"}, 167 | {"SLOVENIA", "Ljuijana"}, 168 | {"SPAIN", "Madrid"}, 169 | {"SWEDEN", "Stockholm"}, 170 | {"SWITZERLAND", "Berne"}, 171 | {"UNITED KINGDOM", "London"}, 172 | {"VATICAN CITY", "---"}, 173 | // North and Central America 174 | {"ANTIGUA AND BARBUDA", "Saint John's"}, {"BAHAMAS", "Nassau"}, 175 | {"BARBADOS", "Bridgetown"}, {"BELIZE", "Belmopan"}, 176 | {"CANADA", "Ottawa"}, {"COSTA RICA", "San Jose"}, 177 | {"CUBA", "Havana"}, {"DOMINICA", "Roseau"}, 178 | {"DOMINICAN REPUBLIC", "Santo Domingo"}, 179 | {"EL SALVADOR", "San Salvador"}, 180 | {"GRENADA", "Saint George's"}, 181 | {"GUATEMALA", "Guatemala City"}, 182 | {"HAITI", "Port-au-Prince"}, 183 | {"HONDURAS", "Tegucigalpa"}, 184 | {"JAMAICA", "Kingston"}, 185 | {"MEXICO", "Mexico City"}, 186 | {"NICARAGUA", "Managua"}, 187 | {"PANAMA", "Panama City"}, 188 | {"ST. KITTS", "-"}, 189 | {"NEVIS", "Basseterre"}, 190 | {"ST. LUCIA", "Castries"}, 191 | {"ST. VINCENT AND THE GRENADINES", "Kingstown"}, 192 | {"UNITED STATES OF AMERICA", "Washington, D.C."}, 193 | // South America 194 | {"ARGENTINA", "Buenos Aires"}, 195 | {"BOLIVIA", "Sucre (legal)/La Paz(administrative)"}, 196 | {"BRAZIL", "Brasilia"}, {"CHILE", "Santiago"}, 197 | {"COLOMBIA", "Bogota"}, {"ECUADOR", "Quito"}, 198 | {"GUYANA", "Georgetown"}, {"PARAGUAY", "Asuncion"}, 199 | {"PERU", "Lima"}, {"SURINAME", "Paramaribo"}, 200 | {"TRINIDAD AND TOBAGO", "Port of Spain"}, 201 | {"URUGUAY", "Montevideo"}, {"VENEZUELA", "Caracas"},}; 202 | 203 | // Use AbstractMap by implementing entrySet() 204 | private static class FlyweightMap extends AbstractMap { 205 | private static class Entry implements Map.Entry { 206 | int index; 207 | 208 | Entry(int index) { 209 | this.index = index; 210 | } 211 | 212 | public boolean equals(Object o) { 213 | return DATA[index][0].equals(o); 214 | } 215 | 216 | public String getKey() { 217 | return DATA[index][0]; 218 | } 219 | 220 | public String getValue() { 221 | return DATA[index][1]; 222 | } 223 | 224 | public String setValue(String value) { 225 | throw new UnsupportedOperationException(); 226 | } 227 | 228 | public int hashCode() { 229 | return DATA[index][0].hashCode(); 230 | } 231 | } 232 | 233 | // Use AbstractSet by implementing size() & iterator() 234 | static class EntrySet extends AbstractSet> { 235 | private int size; 236 | 237 | EntrySet(int size) { 238 | if (size < 0) 239 | this.size = 0; 240 | // Can't be any bigger than the array: 241 | else if (size > DATA.length) 242 | this.size = DATA.length; 243 | else 244 | this.size = size; 245 | } 246 | 247 | public int size() { 248 | return size; 249 | } 250 | 251 | private class Iter implements Iterator> { 252 | // Only one Entry object per Iterator: 253 | private Entry entry = new Entry(-1); 254 | 255 | public boolean hasNext() { 256 | return entry.index < size - 1; 257 | } 258 | 259 | public Map.Entry next() { 260 | entry.index++; 261 | return entry; 262 | } 263 | 264 | public void remove() { 265 | throw new UnsupportedOperationException(); 266 | } 267 | } 268 | 269 | public Iterator> iterator() { 270 | return new Iter(); 271 | } 272 | } 273 | 274 | private static Set> entries = new EntrySet( 275 | DATA.length); 276 | 277 | public Set> entrySet() { 278 | return entries; 279 | } 280 | } 281 | 282 | // Create a partial map of 'size' countries: 283 | static Map select(final int size) { 284 | return new FlyweightMap() { 285 | public Set> entrySet() { 286 | return new EntrySet(size); 287 | } 288 | }; 289 | } 290 | 291 | static Map map = new FlyweightMap(); 292 | 293 | public static Map capitals() { 294 | return map; // The entire map 295 | } 296 | 297 | public static Map capitals(int size) { 298 | return select(size); // A partial map 299 | } 300 | 301 | static List names = new ArrayList(map.keySet()); 302 | 303 | // All the names: 304 | public static List names() { 305 | return names; 306 | } 307 | 308 | // A partial list: 309 | public static List names(int size) { 310 | return new ArrayList(select(size).keySet()); 311 | } 312 | 313 | public static void main(String[] args) { 314 | System.out.println(capitals(10)); 315 | System.out.println(names(10)); 316 | System.out.println(new HashMap(capitals(3))); 317 | System.out.println(new LinkedHashMap(capitals(3))); 318 | System.out.println(new TreeMap(capitals(3))); 319 | System.out.println(new Hashtable(capitals(3))); 320 | System.out.println(new HashSet(names(6))); 321 | System.out.println(new LinkedHashSet(names(6))); 322 | System.out.println(new TreeSet(names(6))); 323 | System.out.println(new ArrayList(names(6))); 324 | System.out.println(new LinkedList(names(6))); 325 | System.out.println(capitals().get("BRAZIL")); 326 | } 327 | } /* 328 | * Output: {ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo, BOTSWANA=Gaberone, 329 | * BULGARIA=Sofia, BURKINA FASO=Ouagadougou, BURUNDI=Bujumbura, 330 | * CAMEROON=Yaounde, CAPE VERDE=Praia, CENTRAL AFRICAN REPUBLIC=Bangui} 331 | * [ALGERIA, ANGOLA, BENIN, BOTSWANA, BULGARIA, BURKINA FASO, BURUNDI, CAMEROON, 332 | * CAPE VERDE, CENTRAL AFRICAN REPUBLIC] {BENIN=Porto-Novo, ANGOLA=Luanda, 333 | * ALGERIA=Algiers} {ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo} 334 | * {ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo} {ALGERIA=Algiers, 335 | * ANGOLA=Luanda, BENIN=Porto-Novo} [BULGARIA, BURKINA FASO, BOTSWANA, BENIN, 336 | * ANGOLA, ALGERIA] [ALGERIA, ANGOLA, BENIN, BOTSWANA, BULGARIA, BURKINA FASO] 337 | * [ALGERIA, ANGOLA, BENIN, BOTSWANA, BULGARIA, BURKINA FASO] [ALGERIA, ANGOLA, 338 | * BENIN, BOTSWANA, BULGARIA, BURKINA FASO] [ALGERIA, ANGOLA, BENIN, BOTSWANA, 339 | * BULGARIA, BURKINA FASO] Brasilia 340 | */// :~ -------------------------------------------------------------------------------- /src/main/java/util/DaemonThreadFactory.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.util.concurrent.ThreadFactory; 4 | 5 | public class DaemonThreadFactory implements ThreadFactory { 6 | @Override 7 | public Thread newThread(Runnable r) { 8 | Thread thread = new Thread(r); 9 | thread.setDaemon(true); 10 | return thread; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/util/Generated.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | public class Generated { 4 | // Fill an existing array: 5 | public static T[] array(T[] a, Generator gen) { 6 | return new CollectionData(gen, a.length).toArray(a); 7 | } 8 | // Create a new array: 9 | @SuppressWarnings("unchecked") 10 | public static T[] array(Class type, 11 | Generator gen, int size) { 12 | T[] a = 13 | (T[])java.lang.reflect.Array.newInstance(type, size); 14 | return new CollectionData(gen, size).toArray(a); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/util/Generator.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | /** 4 | * Created by DengWenzhe on 3/18/17. 5 | */ 6 | public interface Generator { 7 | T next(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/util/MapEntry.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.util.Map; 4 | 5 | public class MapEntry implements Map.Entry { 6 | private K key; 7 | private V value; 8 | public MapEntry(K key, V value) { 9 | this.key = key; 10 | this.value = value; 11 | } 12 | public K getKey() { return key; } 13 | public V getValue() { return value; } 14 | public V setValue(V v) { 15 | V result = value; 16 | value = v; 17 | return result; 18 | } 19 | public int hashCode() { 20 | return (key==null ? 0 : key.hashCode()) ^ 21 | (value==null ? 0 : value.hashCode()); 22 | } 23 | public boolean equals(Object o) { 24 | if(!(o instanceof MapEntry)) return false; 25 | MapEntry me = (MapEntry)o; 26 | return 27 | (key == null ? 28 | me.getKey() == null : key.equals(me.getKey())) && 29 | (value == null ? 30 | me.getValue()== null : value.equals(me.getValue())); 31 | } 32 | public String toString() { return key + "=" + value; } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/util/Maps.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.util.*; 4 | import java.util.concurrent.*; 5 | 6 | import static util.Print.*; 7 | 8 | public class Maps { 9 | public static void printKeys(Map map) { 10 | printnb("Size = " + map.size() + ", "); 11 | printnb("Keys: "); 12 | print(map.keySet()); // Produce a Set of the keys 13 | } 14 | public static void test(Map map) { 15 | print(map.getClass().getSimpleName()); 16 | map.putAll(new CountingMapData(25)); 17 | // Map has 'Set' behavior for keys: 18 | map.putAll(new CountingMapData(25)); 19 | printKeys(map); 20 | // Producing a Collection of the values: 21 | printnb("Values: "); 22 | print(map.values()); 23 | print(map); 24 | print("map.containsKey(11): " + map.containsKey(11)); 25 | print("map.get(11): " + map.get(11)); 26 | print("map.containsValue(\"F0\"): " 27 | + map.containsValue("F0")); 28 | Integer key = map.keySet().iterator().next(); 29 | print("First key in map: " + key); 30 | map.remove(key); 31 | printKeys(map); 32 | map.clear(); 33 | print("map.isEmpty(): " + map.isEmpty()); 34 | map.putAll(new CountingMapData(25)); 35 | // Operations on the Set change the Map: 36 | map.keySet().removeAll(map.keySet()); 37 | print("map.isEmpty(): " + map.isEmpty()); 38 | } 39 | public static void main(String[] args) { 40 | test(new HashMap()); 41 | test(new TreeMap()); 42 | test(new LinkedHashMap()); 43 | test(new IdentityHashMap()); 44 | test(new ConcurrentHashMap()); 45 | test(new WeakHashMap()); 46 | } 47 | } /* Output: 48 | HashMap 49 | Size = 25, Keys: [15, 8, 23, 16, 7, 22, 9, 21, 6, 1, 14, 24, 4, 19, 11, 18, 3, 12, 17, 2, 13, 20, 10, 5, 0] 50 | Values: [P0, I0, X0, Q0, H0, W0, J0, V0, G0, B0, O0, Y0, E0, T0, L0, S0, D0, M0, R0, C0, N0, U0, K0, F0, A0] 51 | {15=P0, 8=I0, 23=X0, 16=Q0, 7=H0, 22=W0, 9=J0, 21=V0, 6=G0, 1=B0, 14=O0, 24=Y0, 4=E0, 19=T0, 11=L0, 18=S0, 3=D0, 12=M0, 17=R0, 2=C0, 13=N0, 20=U0, 10=K0, 5=F0, 0=A0} 52 | map.containsKey(11): true 53 | map.get(11): L0 54 | map.containsValue("F0"): true 55 | First key in map: 15 56 | Size = 24, Keys: [8, 23, 16, 7, 22, 9, 21, 6, 1, 14, 24, 4, 19, 11, 18, 3, 12, 17, 2, 13, 20, 10, 5, 0] 57 | map.isEmpty(): true 58 | map.isEmpty(): true 59 | ... 60 | */ -------------------------------------------------------------------------------- /src/main/java/util/Print.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.io.*; 4 | 5 | public class Print { 6 | // Print with a newline: 7 | public static void print(Object obj) { 8 | System.out.println(obj); 9 | } 10 | // Print a newline by itself: 11 | public static void print() { 12 | System.out.println(); 13 | } 14 | // Print with no line break: 15 | public static void printnb(Object obj) { 16 | System.out.print(obj); 17 | } 18 | // The new Java SE5 printf() (from C): 19 | public static PrintStream 20 | printf(String format, Object... args) { 21 | return System.out.printf(format, args); 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/util/RandomGenerator.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.util.concurrent.ThreadLocalRandom; 4 | 5 | /** 6 | * Created by DengWenzhe on 3/18/17. 7 | */ 8 | public class RandomGenerator { 9 | private static ThreadLocalRandom random = ThreadLocalRandom.current(); 10 | 11 | private static char[] chars = ("abcdefghijklmnopqrstuvwxyz" 12 | + "ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray(); 13 | 14 | public static class Boolean implements Generator { 15 | public java.lang.Boolean next() { 16 | return random.nextBoolean(); 17 | } 18 | } 19 | 20 | public static class Byte implements Generator { 21 | public java.lang.Byte next() { 22 | return (byte) random.nextInt(); 23 | } 24 | } 25 | 26 | public static class Character implements Generator { 27 | public java.lang.Character next() { 28 | return chars[random.nextInt(chars.length)]; 29 | } 30 | } 31 | 32 | public static class String implements Generator{ 33 | private int length = 7; 34 | 35 | public String() {} 36 | 37 | public String(int length) { 38 | this.length = length; 39 | } 40 | 41 | @Override 42 | public java.lang.String next() { 43 | char[] buf = new char[length]; 44 | for (int i = 0; i < length; i++) { 45 | buf[i] = chars[random.nextInt(length)]; 46 | } 47 | return new java.lang.String(buf); 48 | } 49 | } 50 | 51 | public static class Short implements Generator { 52 | public java.lang.Short next() { 53 | return (short) random.nextInt(); 54 | } 55 | } 56 | 57 | public static class Integer implements Generator { 58 | private int mod = 10000; 59 | 60 | public Integer() { 61 | } 62 | 63 | public Integer(int modulo) { 64 | mod = modulo; 65 | } 66 | 67 | public java.lang.Integer next() { 68 | return random.nextInt(mod); 69 | } 70 | } 71 | 72 | public static class Long implements Generator { 73 | private int mod = 10000; 74 | 75 | public Long() { 76 | } 77 | 78 | public Long(int modulo) { 79 | mod = modulo; 80 | } 81 | 82 | public java.lang.Long next() { 83 | return new java.lang.Long(random.nextInt(mod)); 84 | } 85 | } 86 | 87 | public static class Float implements Generator { 88 | public java.lang.Float next() { 89 | return random.nextFloat(); 90 | } 91 | } 92 | 93 | public static class Double implements Generator { 94 | public java.lang.Double next() { 95 | return random.nextDouble(); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/util/TextFile.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.io.*; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.TreeSet; 7 | 8 | public class TextFile extends ArrayList { 9 | /** 10 | * 11 | */ 12 | private static final long serialVersionUID = -7862048067122202787L; 13 | 14 | // Read a file as a single string: 15 | public static String read(String fileName) { 16 | StringBuilder sb = new StringBuilder(); 17 | try { 18 | BufferedReader in = new BufferedReader(new FileReader(new File( 19 | fileName).getAbsoluteFile())); 20 | try { 21 | String s; 22 | while ((s = in.readLine()) != null) { 23 | sb.append(s); 24 | sb.append("\n"); 25 | } 26 | } finally { 27 | in.close(); 28 | } 29 | } catch (IOException e) { 30 | throw new RuntimeException(e); 31 | } 32 | return sb.toString(); 33 | } 34 | 35 | // Write a single file in one method call: 36 | public static void write(String fileName, String text) { 37 | try { 38 | PrintWriter out = new PrintWriter( 39 | new File(fileName).getAbsoluteFile()); 40 | try { 41 | out.print(text); 42 | } finally { 43 | out.close(); 44 | } 45 | } catch (IOException e) { 46 | throw new RuntimeException(e); 47 | } 48 | } 49 | 50 | // Read a file, split by any regular expression: 51 | public TextFile(String fileName, String splitter) { 52 | super(Arrays.asList(read(fileName).split(splitter))); 53 | // Regular expression split() often leaves an empty 54 | // String at the first position: 55 | if (get(0).equals("")) 56 | remove(0); 57 | } 58 | 59 | // Normally read by lines: 60 | public TextFile(String fileName) { 61 | this(fileName, "\n"); 62 | } 63 | 64 | public void write(String fileName) { 65 | try { 66 | PrintWriter out = new PrintWriter( 67 | new File(fileName).getAbsoluteFile()); 68 | try { 69 | for (String item : this) 70 | out.println(item); 71 | } finally { 72 | out.close(); 73 | } 74 | } catch (IOException e) { 75 | throw new RuntimeException(e); 76 | } 77 | } 78 | 79 | // Simple test: 80 | public static void main(String[] args) { 81 | String file = read("src/net/mindview/util/TextFile.java"); 82 | write("test.txt", file); 83 | TextFile text = new TextFile("test.txt"); 84 | text.write("test2.txt"); 85 | // Break into unique sorted list of words: 86 | TreeSet words = new TreeSet(new TextFile( 87 | "src/net/mindview/util/TextFile.java", "\\W+")); 88 | // Display the capitalized words: 89 | System.out.println(words.headSet("a")); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/ch15generic/LinkedStackTest.java: -------------------------------------------------------------------------------- 1 | package ch15generic; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Assert; 6 | 7 | /** 8 | * Created by DengWenzhe on 3/5/17. 9 | */ 10 | public class LinkedStackTest { 11 | @org.junit.Test 12 | public void push() throws Exception { 13 | LinkedStack stack = new LinkedStack<>(); 14 | stack.push("a"); 15 | stack.push("b"); 16 | 17 | assertFalse(stack.isEmpty()); 18 | } 19 | 20 | @org.junit.Test 21 | public void pop() throws Exception { 22 | LinkedStack stack = new LinkedStack<>(); 23 | stack.push("a"); 24 | stack.push("b"); 25 | 26 | assertEquals(2, stack.size()); 27 | } 28 | 29 | } --------------------------------------------------------------------------------