[关闭]
@delight 2015-01-10T14:24:21.000000Z 字数 1801 阅读 2007

java并发编程实战读书笔记

java concurrent base


并发编程实际上极其复杂,有很多绝对值得去看的建议。
1. 不要在构造器里面调用可变函数(虚函数),这是所谓的安全构造需求;
2. 最简单的线程安全类是不可变类,不可变类有如下硬性要求:
* 对象创建以后就不能修改
* 对象所有域都是final
* 对象是安全构造的
3. 所谓可见性指的是a线程修改了变量,b线程可以知道这种修改;所谓原子性指的是a线程在修改变量时,b线程不会干扰这种修改;
4. 所谓安全发布,必须满足以下条件之一:
* 在静态初始化函数中初始化一个对象引用
* 将对象的引用保存到volatile类型或者AtomicReferance对象之中
* 将对象的应用保存到某个正确构造对象的final域中
* 将对象引用保存到一个由锁保护的域中
4. volatile变量只能保证可见性,无法保证原子性;加锁则都可以保证(但是会繁琐一些)。
5. 不要在构造器中调用新的线程,这会导致不安全发布;正确的做法是使用静态工厂函数,构造完毕后再启动线程(或者做其他发布);
6. 最简单维持线程安全的方法是使用局部变量(栈封闭),其次是使用原子类,包括现场本地存储类ThreadLocal<>
7. 大多数情况下,我们无须直接使用Thread这种基础类,java提供了很多适用范围广泛的组件,包括:
8. 并发容器类,使用java.util.concurrent中定义的包括ConcurrentHashMap, CopyOnWriteArrayListConcurrentLinkedQueueBlockingQueueBlockingDeque),以及ConcurrentSkipListMapConcurrentSkipListSet(作为SortedMapSortedSet的替代品).BlockingQueuetakeput时,如果没有元素/空间就会阻塞;
9. 如果线程被中断,会抛出InterruptedException如果是Runnable的对象,是不可以直接抛出这个异常的,必须捕获并使用Thread.currentThread().interrupt()恢复中断;其他类型的对象倒是无所谓,可以直接抛出或者捕获清理后重新抛出;
10. 闭锁。CountDownLatch可以用来等待计数,FutureTask是一种Callable,可以通过get来获得结果(或者阻塞),Semaphore用来对资源进行限制计数,可以用来实现资源池,使用acquire获得一个资源,使用release释放一个资源,Barrier用来实现分段任务,当所有任务都到达Barrier时,任务继续,否则抛出BrokenBarrierException异常。本章给出了一个缓存的例子。
11. Executor框架。Executor是一个接口,只规定了execute一个接口(其参数是一个Runnable class);Executors包含生产线程池的几个静态方法,如newFixedThreadPool(固定大小),newCachedThreadPool(无限增长)和newSingleThreadExecutor(单线程串行),和newScheduledThreadPool(定时执行)。如果这些都不能满足需求,可以直接使用ThreadPoolExecutor自己灵活构造线程池
12. ExecutorService接口在Executor接口的基础上增加了生命周期,可以使用shutdownshutdownNowawaitTermination等方法进行生命周期(运行、关闭和已终止)控制和感知。
13. ExecutorServicesubmit方法用于提交一个任务并返回一个Future,使用这个结果可以控制任务的生命周期;
14. 线程的超时:一般可以用重载的getawait等方法指定超时时间;
15. 线程的取消:习惯上使用一个volatile变量作为取消标志,但是如果线程阻塞了,这个方法就不好用了。最佳方式是使用中断(Future.cancel),注意需要处理好相关的异常;
16. 可以通过继承Thread重载interrupt方法来将中断处理封闭在异常类中;可以通过使用ThreadPoolExecutor中的newTaskFor静态方法由Callable生产RunnableFuture

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注