多线程学习笔记

多线程学习记录

同步类容器

  1. ConcurrentModificationException // 一边遍历一边修改会触发的异常(并发修改)

  2. Vector HashTable 由 Collections工具类中synchronized**方法

并发类容器

ConcurrentMap (相当于分表,分库的思想)
  • 核心思想: 减小锁的粒度从而降低锁的竞争
  • 详细说明: 采用段(Segment),每个段其实就是一个小的HashTable,只要多个修改操作不在同一个段上就可以并发进行,把一个整体分成了16个段,也就是最高支持16个线程的并发修改操作,并且代码中大多共享变量使用volatile关键字声明,目的是第一时间获取修改的内容,性能非常好
  • 常用实现有: ConcurrentHashMap、ConcurrentSkipListMap(支持并发排序功能)
CopyOnWrite(简称COW, 读写分离思想)
  • 核心思想: 读写分离思想
  • 详细说明: 写的时候先复制当前容器,在复制出来的容器中修改,修改完成之后,把原容器引用指向修改之后的值。期间如果有读的操作,会访问原容器。好处是可以对容器进行并发的读,而不需要加锁。因为当前容器不会被修改。
  • 试用场景: 读多写少的情况, 因为每次写都要复制原地址
  • 常用的实现: CopyOnWriteArrayList、CopyOnWriteArraySet
3. Queue
阻塞(BlockingQueue)
  • ArrayBlockingQueue(基于数组的阻塞队列实现,也叫有界队列):

    • 维护了一个定长数组,以便缓存队列中的数据对象
    • 其内部没有实现读写分离
    • 生产者和消费不能完全并行
    • 可以指定先进先出或者先进后出
  • LinkedBlockingQueue(基于链表的阻塞队列):

    • 与ArrayBlockingQueue类似,内部维持着一个数据缓冲队列(该队列由一个链表构成)
    • 可以高效的处理并发数据,是因为其内部实现采用分离锁(读写分离两个锁)
    • 生产者和消费可以完全并行
    • 无界队列
  • SynchronousQueue(一种没有缓冲的队列):

    • 没有缓冲的队列
    • 生产者生产的数据直接被消费消费
    • put放, take拿
  • PriorityBlockingQueue(基于优先级的阻塞队列):

    • 优先级的判断通过构造函数传入的Compator对象来决定的
    • 传入队列的对象必须实现Comparable接口
    • take的时候排序
    • 内部控制线程同步的锁采用的是公平锁
    • 无界队列
  • DelayQueue(带有延迟时间的Queue):

    • 其中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素
    • 传入队列的对象必须实现Delayed接口
    • 无界队列
    • 应用场景很多,比如对缓存超时的数据进行移除,任务超时处理,空闲连接的关闭等
非阻塞(ConcurrentLinkedQueue)
  • 不允许null元素
  • 先进先出
  • add,offer: 都是加入元素方法(在ConcurrentLinkedQueue中,这俩个方法没有任何区别)
  • poll,peek: 都是取头元素节点,区别在于前者会删除元素,后者不会。
4. Futrue模式(异步访问,Ajax)
  • 用户无须一直等待请求的结果,可以继续浏览或操作其他内容
  • 适用场景: 异步, 全双工模式
5. MasterWorker(将大任务分解成若干个小任务,并行执行,从而提高系统的吞吐量)
  • 并行计算模式
  • 核心思想: Master进程和Worker进程,Master负责接收和分配任务,Worker负责处理子任务,当各个Worker子进程处理完成后,会将结果返回给Master,由Master做归纳和总结。
6. 生产消费模式
  • 类似MQ, 若干个生产者与若干个消费者
7. 多任务线程框架

Executor框架Executors,他扮演线程工厂的角色,我们通过Executors创建线程池
- newFixedThreadPool(), 创建一个固定数量的线程池
- 当一个任务进来的时候,先看有没有空闲线程,如果有空闲直接执行,如果没有空闲先放到队列中
- 考虑任务过多易发生OOM

  • newSingleThreadExecutor(),创建一个线程的线程池,若空闲则执行,若没有空闲线程则暂缓在任务列队中。

    • 与newFixedThreadPool相同只是线程数量为1
  • newCachedThreadPool()方法,返回一个可根据实际情况调整线程个数的线程池,不限制最大线程数量,若有任务,则创建线程,若无任务则不创建线程。如果没有任务则线程在60s后自动回收(空闲时间60s)

    • 默认为0,来一个线程创建一个线程
    • 采用SynchronousQueue(一种没有缓冲的队列)
    • 当线程空闲60s自动释放资源
  • newScheduledThreadPool()方法,该方法返回一个SchededExecutorService对象

    • DelayQueue(带有延迟时间的Queue)
    • 定时job
  • ++ThreadPoolExecutor:++ 所有功能的构造器,如果自身提供的不满足要求可以自己实现一个ThreadPoolExecutor

8. 自定义线程池
public ThreadPoolExecutor(int corePoolSize, // 核心线程数
                      int maximumPoolSize,  // 最大线程数
                      long keepAliveTime,   // 线程存活时长
                      TimeUnit unit,        // 与keepAliveTime配合使用
                      BlockingQueue<Runnable> workQueue, // 任务队列
                      ThreadFactory threadFactory,
                      RejectedExecutionHandler handler) // 拒绝策略
  • 有界队列与无界队列参数的区别

    • 有界队列: 若有新的任务需要执行,看有没有空闲线程如果有直接执行,如果没有把任务放入到队列中,如果队列已满则判断corePoolSize是否小于maximumPoolSize如果小于则创建新线程,否则采取拒绝策略

    • 无界队列:

      • 与有界队列相比,除非系统资源耗尽,否则无界的任务队列不存在任务入队失败的情况
      • 当有新任务到来,系统的线程数小于corePoolSize时,则新建线程执行任务,当达到corePoolSize后,就不会继续增加。若后续仍有新的任务加入,而没有空闲的线程资源,则任务直接进入队列等待
      • 若任务创建和处理的速度差异很大,无界队列会保持快速增长,直到耗尽系统内存
    • JDK拒绝策略:

      • AbortPolicy: 直接抛出导演阻止系统正常工作
      • CallerRunsPolicy: 只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务
      • DiscardOldestPolicy:丢弃最老的一个请求,尝试再次提交当前任务
      • DiscardPolicy:丢弃无法处理的任务,不给予任何处理
      • 自定义策略需要实现 RejectedExecutionHandler 接口
9. Executors框架
  • shutdown() 与 shutdownNow() 类似kill与kill -9
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值