Android技术知识Android进阶之路Android开发

并发整理(三)— 并发集合类与线程池

2017-05-21  本文已影响798人  kachidokima

并发整理最后一篇,之前两篇
并发整理(一)— Java并发底层原理
并发整理(二)— Java线程与锁

这篇讲的主要是JDK中运用之前说的并发基础来包装的一些类给开发者来并发调用,仔细研究这些有利于我们加深对并发处理的理解

ConcurrentHashMap

HashMap是非线程安全的,如果在多线程下使用很容易形成环状链表

HashMap死循环问题

关于HashMap,java8也做了很多改进可以看下面的文章

Java8重新认识HashMap

HashTable虽然是线程安全的但是其会把每个操作都会加锁,会严重影响性能所以java推荐使用ConcurrentHashMap来在并发环境下代替HashMap。但是不同的版本有不同的实现方法,主要看以下

注:源码内容太多,所以我没有贴代码,可以自行结合先说的逻辑看源码

Java7

以前的版本主要采用的锁分段技术,主要以下:

探索 ConcurrentHashMap 高并发性的实现机制

Java8

Node的不同

扩容

前面说了在HashMap的时候很容易由于扩容问题在并发中造成环节点,但是8中的ConcurrentHashMap也摒弃了之前的分段锁,使用了更优美的方法:

Put操作

由于摒弃了分段锁,所以不再是以前那样的两次hash,这次通过不允许全部的KEYValue为null,用CAS操作和每个桶加锁来保证并发的安全:

get操作

这个比较简单,而且ConcurrentHashMap直接把查找节点封装到了桶,直接调用find就好

ConcurrentHashMap源码分析(JDK8版本)

ConcurrentLinkedQueue

与HashMap的同步处理相比,这个简单的多

ConcurrentLinkedQueue采用非阻塞,不加锁的CAS算法来保证并发的问题

类中有volatile修饰的head和tail变量,下面以入队列offer为例,出队列是一样的逻辑

因为ConcurrentLinkedQueue是无界的所以offer始终返回true,不要通过返回值去判断入队成功

ConcurrentLinkedQueue源码分析

非阻塞算法在并发容器中的实现

BlockingQueue

阻塞队列完全是由生产者与消费者场景产生的,其在队列基础上支持两个阻塞的插入与删除操作

原理

ArrayBlockingQueue为例,使用并发中典型的通知模式,就比如,如果队列满了,则添加就会阻塞,直到消费了一个之后再通知生产者当前队列可以用

Executor框架

结构

主要由以下组成

Executor结构图

ThreadPoolExecutor

流程

其是Executor的一个主要实现了,下面三个线程池都继承它,其内部有一个核心线程池corePool,一个最大线程池maximumPool,和一个执行队列BlockingQueue,其执行的逻辑如下:

ThreadPoolExecutor执行图
  1. 如果当前线程少于corePoolSize则获取全局锁,创建线程来执行任务
  2. 如果允运行的线程大于corePoolSize则把任务加入执行队列BlockingQueue
  3. 如果队列都满了,那就再获取全局锁,创建新线程执行任务
  4. 如果maximumPool都满了,那就使用RejectExecutionHandler拒绝任务

其中线程池创建线程时会将线程封装在一个Worker里面,每次worker执行完任务后会循环获取任务队列中的任务来执行

一般直接用ThreadPoolExecutor还是太复杂,所以用下面四个:

FixedThreadPool

可重用固定线程数的线程池,将corePoolSizemaximumPool设置相同,所以没有了第3步,并且其内使用LinkedBlockingQueue来作为工作队列,所以只要小于Integer.MAX_VALUE,都会入队,如果池满了就一直等待,线程Worker做完任务如果没有新的则立即结束

SingleThreadExecutor

单个线程的ExecutorcorePoolSizemaximumPoolSize都是1,维护一个工作队列

CachedThreadPool

有缓存线程的线程池,corePoolSize为0,maximumPoolSizeInteger.MAX_VALUE,并且每个线程Worker执行完后会等待60s没有任务才关闭,其内部工作队列为SynchronousQueue是没有容量的阻塞队列,所以每个任务只要没有空闲线程,都会直接开一个新的线程Worker,极端情况下CachedThreadPool会因为创建过多的线程而耗尽CPU和内存资源

ScheduledThreadPoolExecutor

支持延时以及周期的执行任务,其将maximumPool置为无效,并且内部使用DelayQueue来周期执行任务

上一篇下一篇

猜你喜欢

热点阅读