第10章
第66条
1、Java中的原子操作:对于所有的变量(除long和double外)读和写操作都是原子的(互斥的)。(不会在写的中途被读取,成为一个奇怪的量,获取的值为写之前,或者是写之后的值)
2、虽然java中的变量是原子操作,但是必要时刻仍需要同步。
3、对于共享的数据,最好同步其动作。
第67条
CopyOnWriteArrayList:并发集合。写操作通过拷贝底层数组+锁实现,读操作不加锁。大量使用会影响使用。适用于读多写少。
缺点:会在某一时间存在一份拷贝,占用内存;只能保证最终一致性。
第68条
线程池:
Executor是一个顶层接口,在它里面只声明了一个方法execute(Runnable),返回值为void,参数为Runnable类型,从字面意思可以理解,就是用来执行传进去的任务的;
ExecutorService接口继承了Executor接口,并声明了一些方法:submit、invokeAll、invokeAny以及shutDown等;
抽象类AbstractExecutorService实现了ExecutorService接口,基本实现了ExecutorService中声明的所有方法;
然后ThreadPoolExecutor继承了类AbstractExecutorService。
Executors是一个工具类,通过简单工厂提供不同的线程池。
Executors提供四种线程池:
newCachedThreadPool :缓存线程池,如果线程池长度超过处理需要,可回收空闲线程,若无可回收,则新建线程。core=0,max=int_max。队列为SynchronousQueue,容量为0,容器相当于通道,本身不存储元素。
newFixedThreadPool : 定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。max=core,队列为LinkedBlockingQueue,容量为MAX_INTEGER。
newScheduledThreadPool : 计划线程池,支持定时及周期性任务执行。队列为LinkedBlockingQueue
newSingleThreadExecutor :单线程线程池,用唯一的线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。core=1,max=1,队列为DelayedWorkQueue
线程和任务:并不是每一个任务到了就会创建一个线程去执行。
当新提交一个任务时:
(1)如果poolSize<corePoolSize,新增加一个线程处理新的任务。
(2)如果poolSize=corePoolSize,新任务会被放入阻塞队列等待。
(3)如果阻塞队列的容量达到上限,且这时poolSize<maximumPoolSize,新增线程来处理任务。
(4)如果阻塞队列满了,且poolSize=maximumPoolSize,那么线程池已经达到极限,会根据饱和策略RejectedExecutionHandler拒绝新的任务。
-
corePoolSize :线程池的基本大小,即在没有任务需要执行的时候线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。这里需要注意的是:在刚刚创建ThreadPoolExecutor的时候,线程并不会立即启动,而是要等到有任务提交时才会启动,除非调用了prestartCoreThread/prestartAllCoreThreads事先启动核心线程。再考虑到keepAliveTime和allowCoreThreadTimeOut超时参数的影响,所以没有任务需要执行的时候,线程池的大小不一定是corePoolSize。
-
maximumPoolSize:
线程池中允许的最大线程数,线程池中的当前线程数目不会超过该值。如果队列中任务已满,并且当前线程个数小于maximumPoolSize,那么会创建新的线程来执行任务。 -
allowCoreThreadTimeOut:
该属性用来控制是否允许核心线程超时退出。If false,core threads stay alive even when idle.If true, core threads use keepAliveTime to time out waiting for work。如果线程池的大小已经达到了corePoolSize,不管有没有任务需要执行,线程池都会保证这些核心线程处于存活状态。可以知道:该属性只是用来控制核心线程的。
keepAliveTime:
如果一个线程处在空闲状态的时间超过了该属性值,就会因为超时而退出。举个例子,如果线程池的核心大小corePoolSize=5,而当前大小poolSize =8,那么超出核心大小的线程,会按照keepAliveTime的值判断是否会超时退出。如果线程池的核心大小corePoolSize=5,而当前大小poolSize =5,那么线程池中所有线程都是核心线程,这个时候线程是否会退出,取决于allowCoreThreadTimeOut。
第69条
并发工具优先于wait和notify
- Executor Framework 线程池
- Concurrent Collection 并发集合
- 同步器
并发集合:
- ConcurrentHashMap
- ConcurrentLinkedDeque
- ConcurrentLinkedQueue
同步器:
- CountDownLatch:一次性障碍,构造参数为int,表示在等待线程被处理之前得达到的数值。
- Semaphore:信号量
- CyclicBarrier:不常用
- Exchanger:不常用
第71条
慎用延迟初始化
虽然降低了初始化的开销,但是却相应的增加了访问的开销。
实例域:采用双重检查模式
静态域:静态工厂构造,VM在构造静态类的时候实现了同步。
第72条
**不要依赖于线程调度器 **
yield:让出cpu时间给其它线程,有可能仍然自己获得cpu时间
不要通过yield以及线程优先级仅能作为应用级别的实现,而不能用其来解决程序中出现的问题