Concurrent包

概述

  1. 是JDK1.5出现的专门应对高并发的包
  2. 内容:BlockingQueue、ConcurrentMap、ExecutorService、Lock、原子性操作

BlockingQueue - 阻塞式队列

概述

  1. 依然遵循**“先进先出”(FIFO)**的原则
  2. 所有的阻塞式队列都是有界的,即队列的大小是固定的
  3. 如果队列已满,则添加操作会被阻塞;如果队列为空,则获取操作会被阻塞
  4. BlockingQueue是阻塞式队列的顶级接口,用的是其实现类
  5. 重要方法
表头抛出异常返回值阻塞定时阻塞
添加addoffer - true/falseputoffer
获取removepoll - nulltakepoll
  1. 阻塞式队列的适用场景:生产消费模型

ArrayBlockingQueue - 阻塞式顺序队列

  1. 底层基于数组存储
  2. 使用时需要指定容量

LinkedBlockingQueue - 阻塞式链式队列

  1. 底层基于链表存储
  2. 使用的时候容量可指定也可不指定,如果指定容量,则此容量不可变。如果不指定容量,则默认Integer.MAX_VALUE–>2的31次方-1,一般会认为这个队列是无界的

PriorityBlockingQueue - 具有优先级的阻塞式队列

  1. 在使用的时候可以指定也可不指定容量,如果不指定容量,则默认为11
  2. 在遍历队列的时候,会对放入其中的元素进行自然排序。但是注意,如果是迭代遍历,则是无序的
  3. 要求放入的元素所对应的类型必须实现Comarable接口

SynchronousQueue - 同步队列

  1. 在使用的时候不需要指定容量,容量默认为1,并且只能为1
  2. 会将这个队列称之为汇合点

BlockingQueue - 阻塞式双端队列

  1. 两个方向都可以进行添加和移除的操作

ConcurrentMap -并发映射

概述

  1. JDK1.5提供用于高并发以及保证安全性的一类映射

ConcurrentHashMap - 并发哈希映射

  1. 底层结构依然是依靠数组+链表

  2. 默认初始容量是16,默认加载因子是0.75,默认扩容增加一倍

  3. 底层采用了叫分桶锁(分段锁)机制,来保证并发性,在后续的版本中,在concurrenthashmap分段锁的基础上引入了读写锁机制:

    • 读锁:允许多个线程同时读,不允许线程写
    • 写锁:只允许一个线程写,不允许线程读
  4. 在JDK1.8中,采用了无锁算法CAS(Compare And Swap - 比较和交换)
    在这里插入图片描述
    对CAS的理解,CAS是一种无锁算法,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
    CAS比较与交换的伪代码可以表示为:
    do{
    备份旧数据;
    基于旧数据构造新数据;
    }while(!CAS( 内存地址,备份的旧数据,新数据 ))
    注:t1,t2线程是同时更新同一变量56的值
    因为t1和t2线程都同时去访问同一变量56,所以他们会把主内存的值完全拷贝一份到自己的工作内存空间,所以t1和t2线程的预期值都为56。
    假设t1在与t2线程竞争中线程t1能去更新变量的值,而其他线程都失败。(失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次发起尝试)。t1线程去更新变量值改为57,然后写到内存中。此时对于t2来说,内存值变为了57,与预期值56不一致,就操作失败了(想改的值不再是原来的值)。
    (上图通俗的解释是:CPU去更新一个值,但如果想改的值不再是原来的值,操作就失败,因为很明显,有其它操作先改变了这个值。)
    就是指当两者进行比较时,如果相等,则证明共享数据没有被修改,替换成新值,然后继续往下运行;如果不相等,说明共享数据已经被修改,放弃已经所做的操作,然后重新执行刚才的操作。容易看出 CAS 操作是基于共享数据不会被修改的假设,采用了类似于数据库的commit-retry 的模式。当同步冲突出现的机会很少时,这种假设能带来较大的性能提升。

  5. 在JDK1.8中引入了红黑树机制。当桶中额元素个数超过8个,则扭转成红黑树;如果节点个数不足7个,则会扭转成链表。扭转成红黑树的初始容量为64

  6. 红黑树:
    a. 本质上一棵自平衡二叉查找树
    b. 查询效率的时间复杂度:O(logn)
    c. 二叉查找树:
    i. 基于二叉树
    ii.左子树都小于根,右子树都大于根
    d. 特点:
    i. 所有的节点非红即黑
    ii. 根节点一定是黑的
    iii. 红节点的子节点一定是黑节点,黑节点的子节点可以是红节点也可以是黑节点
    iv. 最底层的叶子节点一定是黑色的空节点
    v. 从根节点到任意一个叶子节点警告的黑色节点的个数一定相同,即黑色节点高度一致
    vi. 新添加的节点颜色一定是红节点
    e. 修正:红黑树的修正过程是一个链式过程(涂色–左旋–右旋)
    i. 当前节点为红,父节点也为红,并且叔父节点也为红,那么需要将父节点以及叔父节点涂黑,然后将祖父节点涂红
    ii. 当前节点为红父节点为红,叔父节点为黑,并且当前节点为右子叶,那么需要以当前节点为轴,进行左旋
    iii.当前节点为红父节点为红,叔父节点为黑,并且当前节点为左子叶,那么需要以父节点为轴进行右旋

ConcurrentNavigableMap—并发导航映射

  1. 这类映射中提供了截取子映射的方法
  2. ConcurrentNavigableMap本身是一个接口,更常使用是它的实现类ConcurrentSkipListMal - 并发跳跃表映射 - 底层是基于跳跃表来存储的
  3. 跳跃表:
    • 使用前提:元素有序
    • 实际使用过程,跳跃表往往不止一层,最上层的跳跃表的元素个数不少于2个
    • 跳跃表适用于查询多,增删少的场景
    • 跳跃表是典型的以空间换时间的产物
    • 当新添元素时,这个元素是否要提取到上一次跳跃表中,遵循“抛硬币原则”
    • 查询的时间复杂度是:O(logn)

ExecutorService - 执行器服务

概述

  1. 线程池的意义:减少线程的创建和销毁,做到线程的重用,以提高资源的利用率
  2. 当线程定义好之后,线程池中没有任何线程
  3. 每过来一个请求,会创建一个线程去处理这个请求,直到线程数达到指定的数量不在创建。这些线程称之为核心线程
  4. 在核心线程数量达到指定数量之前,每次的请求都会创建一个新的核心线程
  5. 核心线程使用完成,不会被销毁,而是会等待下一个任务
  6. 如果核心线程被占满,则后续的请求会放入该线程的工作队列中。工作队列本质上是阻塞式队列
  7. 如果工作队列被全部占用,则信赖的请求会交给临时线程处理
  8. 临时线程再使用完成之后不会立即销毁而是会存活一段指定的时间,如果这段时间内没有请求处理,则该临时线程才会被销毁
  9. 如果临时线程被全部占用,则后续的请求会交给 拒绝执行处理器来进行拒绝处理

Callable线程

  1. Callable执行完成之后会有返回结果,所以泛型限定结果类型
  2. Runable和Callable的区别:
    a. 返回值:Runable没有返回值;Callable有返回值
    b. 启动方式:Runable可以通过Thread启动也可以通过线程池启动;Callable只能通过线程池启动
    c. 容错机制:Runableo不允许抛出异常,所以不能以全局方式(例如Spring中的异常通知)处理;但是Callable允许以全局方式处理

ScheduledExecutorService - 定时执行器服务

  1. 起到定时执行的效果
  2. 是很多定时器底层的实现

ForkJoinPool - 分叉合并池

  1. 分叉:将任务进行分解,将一个大任务拆分成多个小的任务分配到不同的核上来执行
  2. 合并:将分叉的执行结果进行合并
  3. 分叉合并的目的:提高CPU的利用率
  4. 分叉合并是适用于任务量比较大的场景
  5. 为了防止因为慢任务导致效率降低,采取了work-stealing(工作窃取)策略:即当一个核上的任务执行完成之后,不会空闲下来而是会随机的去其他核上去“偷”一个任务过来执行

Lock

概述

  1. Lock是JDK1.5提供的一个接口:有效的降低死锁产生的几率,Lock相对 synchronized而言更加的灵活
  2. 用的更多的是它的实现类:ReentrantLock
  3. 公平和非公平策略:锁如果不指定,默认是非公平策略
  4. 读写锁:
    a. 读锁:允许多个线程读但是不允许写
    b. 写锁:只允许一个线程写但是不允许读

其他

  1. CountDownLatch - 闭锁/线程递减锁。用于进行线程的计数,当达到指定的 计数的时候,会放开阻塞允许后续线程执行
  2. CyclicBarrier:栅栏。用于进行线程的计数
  3. Exchanger:交换机。用于交换两个线程之间的信息
  4. Semaphore:信号量。如果有空余的信号,则来的线程可以取得信号执行,
    如果没有空余信号,来的线程就会被阻塞直到有信号被空出 - 实际过程中往往 用于进行"限流"
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值