@lambeta
2016-09-19T23:17:38.000000Z
字数 13256
阅读 564
translation
第1章到第8章,每一章都是以习题作为结尾的,这些习题旨在测试你对章节内容的理解程度。本附录会给出这些习题的答案。
答案是false:默认的线程名称以Thread-前缀开头。
通过调用接收线程名称的Thread构造函数或者void setName(String name)方法,你可以给线程一个非默认的名称。
java.lang.IllegalThreadStateException。清单A-1 中断一条睡眠中的后台线程
public class IntSleep{public static void main(String[] args){Runnable r = new Runnable(){@Overridepublic void run(){while (true){System.out.println("hello");try{Thread.sleep(100);}catch (InterruptedException ie){System.out.println("interrupted");break;}}}};Thread t = new Thread(r);t.start();try{Thread.sleep(2000);}catch (InterruptedException ie){}t.interrupt();}}
清单 A-2 修复存在问题的账户检查程序
public class CheckingAccount{private volatile int balance;public CheckingAccount(int initialBalance){balance = initialBalance;}public synchronized boolean withdraw(int amount){if (amount <= balance){try{Thread.sleep((int) (Math.random() * 200));}catch (InterruptedException ie){}balance -= amount;return true;}return false;}public static void main(String[] args){final CheckingAccount ca = new CheckingAccount(100);Runnable r = new Runnable(){@Overridepublic void run(){String name = Thread.currentThread().getName();for (int i = 0; i < 10; i++)}};Thread thdHusband = new Thread(r);thdHusband.setName("Husband");Thread thdWife = new Thread(r);thdWife.setName("Wife");thdHusband.start();thdWife.start();} }
这段程序使用了volatitle关键字应对潜在的缓存问题,并用synchronized关键字满足了互斥的需要。
清单A-3 使用wait()以及notifyAll()来创建一个更高级的并发构造
public class Await{static volatile int count;public static void main(String[] args){Runnable r = () ->{Thread curThread = Thread.currentThread();System.out.printf("%s has entered runnable and is " +"waiting%n", curThread.getName());synchronized(Await.class){count++;try{Thread.sleep(2000);while (count < 3)Await.class.wait();}catch (InterruptedException ie){}}System.out.printf("%s has woken up and is " +"terminating%n",curThread.getName());};Thread thdA = new Thread(r, "thdA");Thread thdB = new Thread(r, "thdB");Thread thdC = new Thread(r, "thdC");thdA.start();thdB.start();thdC.start();r = new Runnable(){@Overridepublic void run(){try{while (count < 3)Thread.sleep(100);synchronized(Await.class){Await.class.notifyAll();}}catch (InterruptedException ie){}}};Thread thd = new Thread(r);thd.start();}}
清单A-4 借助Timer,反复地将一个星号前后移动
import java.util.Timer;import java.util.TimerTask;public class Untitled{static enum Direction { FORWARDS, BACKWARDS }public static void main(String[] args){TimerTask task = new TimerTask(){final static int MAXSTEPS = 20;volatile Direction direction = Direction.FORWARDS;volatile int steps = 0;@Overridepublic void run(){switch (direction){case FORWARDS : System.out.print("\b ");System.out.print("*");break;case BACKWARDS: System.out.print("\b ");System.out.print("\b\b*");}if (++steps == MAXSTEPS){direction =(direction == Direction.FORWARDS)? Direction.BACKWARDS: Direction.FORWARDS;steps = 0;}}};Timer timer = new Timer();timer.schedule(task, 0, 100);}}
清单A-5 基于Executor的线程计数
import java.util.concurrent.Executors;import java.util.concurrent.ExecutorService;public class CountingThreads{public static void main(String[] args){Runnable r = new Runnable(){@Overridepublic void run(){String name = Thread.currentThread().getName();int count = 0;while (true)System.out.println(name + ": " + count++);}};ExecutorService es = Executors.newFixedThreadPool(2);es.submit(r);es.submit(r);}}
12. 清单A-6展示了第5章中的CountingThreads应用程序,线程的名称是自定义的:
清单A-6 基于Executor的A、B线程计数
import java.util.concurrent.Executors;import java.util.concurrent.ExecutorService;import java.util.concurrent.ThreadFactory;public class CountingThreads{public static void main(String[] args){Runnable r = new Runnable(){@Overridepublic void run(){String name = Thread.currentThread().getName();int count = 0;while (true)System.out.println(name + ": " + count++);}};ExecutorService es =Executors.newSingleThreadExecutor(new NamedThread("A"));es.submit(r);es = Executors.newSingleThreadExecutor(new NamedThread("B"));es.submit(r);}}class NamedThread implements ThreadFactory{private volatile String name; // newThread() could be called by a// different threadNamedThread(String name){this.name = name;}@Overridepublic Thread newThread(Runnable r){return new Thread(r, name);}}
### 第6章:同步器
1. 同步器指的是控制通用同步方法的类。
2. 倒计时门闩会导致一条或多条线程在“门口”一直等待直到另一条线程打开这扇门,线程才得以继续运行。它是由一个计数变量和两个操作组成的,这两个操作分别是“导致一条线程等待直到计数变为0”以及“递减计数变量”。
3. 调用CountDownLatch的void countDown()方法,当计数降至0时释放所有等待线程。
4. 同步屏障允许一组线程彼此互相等待,直到抵达到某个公共的屏障点。因为该屏障在等待线程被释放之后可以重用,所以称它为可循环使用的屏障。该同步器对于这类数量固定,并且互相之间必须不时等待彼此的多线程应用很有用。
5. 答案是false:当有线程正在等待时该同步屏障被重置了(通过 reset()方法)以及当同步屏障在await()方法被调用或任意线程正在等待时同步屏障被打破,CyclicBarrier的int await()方法就会抛出java.util.concurrent.BrokenBarrierException。
6. 交换器提供了一个线程彼此之间能够交换对象的同步点。每条线程都会往这个交换器的exchange()方法传入一些对象,匹配伙伴线程,同时接收伙伴线程中的对象作为返回值。
7. Exchanger的V exchange(V x)会在这个交互点上等待其他线程到达(除非调用线程被中断了),之后将所给对象传入其中,接收其它线程的对象作为返回。
8. 信号量维护了一组许可证(permit)来约束访问被限制资源的线程数。当没有可用的许可证时,线程的获取尝试会一直阻塞直到其它的线程释放一个许可证。
9. 信号量有两种类型,分别是计数信号量(当前值可以被递增加1)和二进制信号量或互斥信号量(当前值只能取0或1)。
10. phaser是一个更加弹性的同步屏障。和同步屏障一样,一个phaser使得一组线程在屏障上等待,在最后一条线程到达之后,这些线程得以继续执行。phaser也提供barrier action的等价操作。和同步屏障协调固定数目的线程不同,一个phaser能够协调不定数目的线程,这些线程可以在任何时候注册。为了实现这一功能,phaser使用了phase和phase值。
11. 类Phaser的int register()方法返回用于分类抵达的phase值。如果这个值是负数,该phaser就会终止,此时注册不产生任何影响。这个数值被称为抵达phase值。
12. 清单A-7展示了在第6章中被调用的PC应用程序。
清单A-7 基于信号量的生产者和消费者
import java.util.concurrent.Semaphore;public class PC{public static void main(String[] args){Shared s = new Shared();Semaphore semCon = new Semaphore(0);Semaphore semPro = new Semaphore(1);new Producer(s, semPro, semCon).start();new Consumer(s, semPro, semCon).start();}}class Shared{private char c;void setSharedChar(char c){this.c = c;}char getSharedChar(){return c;}}class Producer extends Thread{private final Shared s;private final Semaphore semPro, semCon;Producer(Shared s, Semaphore semPro, Semaphore semCon){this.s = s;this.semPro = semPro;this.semCon = semCon;}@Overridepublic void run(){for (char ch = 'A'; ch <= 'Z'; ch++){try{semPro.acquire();}catch (InterruptedException ie){}s.setSharedChar(ch);System.out.println(ch + " produced by producer.");semCon.release();}}}class Consumer extends Thread{private final Shared s;private final Semaphore semPro, semCon;Consumer(Shared s, Semaphore semPro, Semaphore semCon){this.s = s;this.semPro = semPro;this.semCon = semCon;}@Overridepublic void run(){char ch;do{try{semCon.acquire();}catch (InterruptedException ie){}ch = s.getSharedChar();System.out.println(ch + " consumed by consumer.");semPro.release();}while (ch != 'Z');}}
清单A-8 基于ReentrantLock的ID生成器
import java.util.concurrent.locks.ReentrantLock;public class ID{private static int counter; // initialized to 0 by defaultprivate final static ReentrantLock lock = new ReentrantLock();public static int getID(){lock.lock();try{int temp = counter + 1;try{Thread.sleep(1);}catch (InterruptedException ie){}return counter = temp;}finally{lock.unlock();}}}
ConcurrentMap是java.util.Map的子接口,声明了额外的原子的方法putIfAbsent()、remove()、replace()。
ArrayBlockingQueue是一个基于数组的有界阻塞队列。LinkedBlockingQueue是一个基于链接节点的非有界阻塞队列。
Fork/Join框架由特定的executor service和线程池构成。executor service可以运行任务,并且这个任务会被分解成较小的任务,它们从线程池中被fork(被不同的线程执行)出来,在join(即它的所有子任务都完成了)之前会一直等待。
Fork/Join框架绝大部分由java.util.concurrent包中的ForkJoinPool、ForkJoinTask、ForkJoinWorkerThread、RecursiveAction、RecursiveTask以及CountedCompleter类组成。
Future<V>实例代表该任务的未完成状态。之后你可以调用poll()方法来轮训这个任务的完成状态或者调用阻塞式的take()方法(译者注:获得结果)。消费者通过调用take()方法获取一个已完成的任务。这个方法在任务已经完成之前会一直阻塞。之后它会返回一个Future<V>对象来表示这一完成的任务,调用Future<V>的get()方法即可获取结果。ExecutorCompletionService<V>来执行任务,这个类实现了CompletionService<V>接口,同时提供executor用于支持任务执行。
AtomicInteger counter = new AtomicInteger(0);int total = counter.incrementAndGet();
和int total = counter--;等价的原子变量如下:
AtomicInteger counter = new AtomicInteger(0);int total = counter.getAndDecrement();