【多线程与高并发】知识点汇总

线程的概念、启动方式、常用方法
  • 继承Thread
  • 实现Runnable接口
  • 实现Callable接口

  • synchronized(Object)
- 不能用String、常量、Integer、Long
- "object"
  • 线程同步
- synchronized
  • 锁的是对象不是代码
  • this、XX.class
  • 锁定方法、非锁定方法可同时执行
  • 锁升级
        - 偏向锁、自旋锁、重量级锁
偏向锁:没有真正加锁
自旋锁:在CPU,占用CPU时间,适用于线程数量少、执行时间短的场景
重量级锁: 在OS(操作系统),不占用CPU时间,适用于数量多、执行时间长的场景

  • volatile
    • 保证线程可见性
        - MESI
        - 缓存一致性协议
  • 禁止指令重排序
- DCL单例
- Double Check Lock
- Mgr06.java

CAS(无锁优化  自旋)
  • Compare And Set
  • cas(V,Expected,NewValue)
- if V == E
  V = New
  otherwise try again or fail
- CPU原语支持,不会被打断
  • ABA问题
        - 加version(版本号),AtomicStampedReference解决该问题
        - A 1.0
        - B 2.0
        - A 3.0
        - cas(version)
        - 如果基础类型,无所谓;引用类型,你的女朋友跟你复合,中间经历了别的男人,就出问题了。

Unsafe
  • 直接操作内存
        - allocateMemory puXX freeMemory pageSize
  • 直接生成类实例
        - allocateInstance
  • 直接操作类或实例变量
        - objectFieldOffset
        - getInt
        - getObject
  • CAS相关操作
        - weakCompareAndSetObject Int Long

JUC包中的同步锁
  • Lock接口
  • ReadWriteLock接口
  • Condition接口
  • ReentrantLock独占锁
  • ReentrantReadWriteLock读写锁
  • CountDownLatch
  • CyclicBarrier
  • Semaphore
  • AbstractOwnableSynchronizer抽象类
  • AbstractQueuedSynchronizer抽象类
  • AbstractQueuedLongSynchronizer抽象类

ReentrantLock
  • 公平锁、非公平锁
  • 队列,如:生产者线程、消费者线程,分别放入两个队列
ReentrantLock vs synchronized
  • ReentrantLock手动加锁、解锁;synchronized系统加锁、解锁
  • ReentrantLock有各种condition(等待队列);synchronized没有队列
  • ReentrantLock底层为AQS实现;synchronized默认实现了4种锁状态的升级

ReadWriteLock
  • 读锁-共享锁
  • 写锁-排他锁

LockSupport
  • 一个线程阻塞工具类
  • 所有的方法都是静态方法
  • 不使用锁的情况下,让线程也能在任意位置阻塞、唤醒

AQS(CLH)
  • Template Method
            Callback Function
            父类默认实现
            子类具体实现
            里面运用了大量的CAS操作
  • Volatile state
        - 具体由子类实现
        - 双向链表,节点node,node里面是thread
  • VarHandle (JDK 9)
        - 普通的属性也能变成原子操作,保证了线程安全
        - 比反射快,直接操纵二进制码

ThreadLocal
  • set
        -  Thread.currentThread.map(ThreadLocal, person)
        - 设到了当前线程的map中
  • 用途
        - 声明式事务,保证同一个Connection

四大引用-强软弱虚
  • 强引用
        - 只要有一个引用指向它(堆),垃圾回收器就不会回收它;应用:普通引用
  • 软引用
        - 当内存不够用时,系统会垃圾回收,先回收一次,如果不够,会把软引用干掉;应用:缓存
  • 弱引用
        - 应用:ThreadLocal,用完之后一定要remove掉
        - 为什么Entry要使用弱引用?若是强引用,即使tl=null,但key的引用依然指向ThreadLocal对象,所以会有内存泄露,而使用弱引用则不会;但还是有内存泄露存在,ThreadLocal被回收,key的值变成null,则导致整个value再也无法被访问到,因此依然存在内存泄露
  • 虚引用
        - 管理堆外内存;应用:给开发JVM的人员使用,当使用虚引用的对象被回收时,通过Queue可以检测到,然后JVM开发人员可以清理堆外内存

多线程容器
  • Vector (自带锁)、Hashtable(基本不用)
  • Hashtable -> ConcurrentHashMap
  • Vector -> Queue
        - CopyOnWriteList、ConcurrentHashMap、ConcurrentSkipListMap
        - Queue List
        - 对线程友好的API offer peek poll
        - BlockingQueue
        - put take -> 阻塞
  • DelayQueue、SynchronousQueue、TransferQueue

线程池
  • Executor接口
  • ExecutorService接口
    • AbstractExecutorService接口
  • Callable接口
    • Callable -> Runnable + ret(返回值)
    • Future -> 存储执行的将来才会产生的结果
    • FutureTask -> Future + Runnable
  • ThreadPoolExecutor
    • corePoolSize  核心线程数
    • maxPoolSize  最大线程数
    • keepAliveTime  存活时间
    • TimeUnit  时间单位
    • BlockingQueue  任务队列
    • ThreadFactory 线程工厂
    • RejectStrategy  拒绝策略
      • Abort  报异常
      • Discard  悄悄扔掉
      • DiscardOld  扔掉队列开头的一个
      • CallerRuns  谁调用谁执行
    • 源码分析
      • Work类
        • Runable AQS
        • thread
      • submit方法
      • execute
        • core、queue、noncore
      • addWorker
        • count++、addWorker start
  • ForkJoinPool
    • 分解汇总的任务
    • 用很少的线程可以执行很多的任务(子任务)ThreadPoolExecutor做不到先执行子任务
    • CPU密集型

Executors - 线程池的工厂
  • SingleThreadExecutor
    • 为什么要有单线程的线程池? 任务队列、生命周期管理
  • CachedThreadPool vs FixedThreadPool
    • CachedThreadPool适用于流量不稳定的情况;FixedThreadPool适用于流量比较固定的情况,可使用并行处理
    • 阿里都不用,自己估算,进行精确定义
  • Scheduled
  • 定时任务线程池
    • quartz cron框架
    • 面试:假如提供一个闹钟服务,订阅这个服务的人特别多,10亿人,怎么优化?
                    - 主服务器把这些任务同步到边缘服务器,在每台服务器上用线程池加上队列

concurrent vs parallel
  • 并发是指任务提交,并行指任务执行
  • 并行是并发的子集,多个CPU同时处理任务

JMH,主要是测试开发人员使用
  • Java Microbenchmark Harness
  • 2013年首发
    • 由JIT的开发人员开发
    • 归于OpenJDK

Disruptor
  • 并发编程框架
  • 特点
    • Disruptor是数组实现的
    • 无锁,高并发,使用环形Buffer,直接覆盖(不用清除)旧的数据,降低GC频率
    • 实现了基于事件的生产者消费者模式(观察者模式)
  • 核心: RingBuffer
    • 环形队列
    • RingBuffer的序号,指向下一个可用的元素
    • 采用数组实现,没有首尾指针
    • 对比ConcurrentLinkedQueue,用数组实现的速度更快
      • 假如长度为8,当添加到第12个元素的时候在哪个序号上呢?用12%8决定
      • 当Buffer被填满的时候到底是覆盖还是等待,由Producer决定
      • 长度设为2的n次幂,利于二进制计算,例如:12%8 = 12 &(8 - 1),pos = num & (size - 1)
  • 开发步骤
    • 定义Event - 队列中需要处理的元素
    • 定义Event工厂,用于填充队列
      • 这里牵扯到效率问题:disruptor初始化的时候,会调用Event工厂,对ringBuffer进行内存的提前分配,GC产生频率会降低
    • 定义EventHandler(消费者),处理容器中的元素
  • ProducerType生产者线程模式
    • ProducerType有两种模式,Producer.MULTI 和 Producer.SINGLE
    • 模式是MULTI,表示在多线程模式下产生sequence
    • 如果确认是单线程生产者,那么可以指定SINGLE,效率会提升
    • 如果是多个生产者(多线程),但模式指定为SINGLE,会出什么问题呢?数据被覆盖
  • 等待策略
    • BlockingWaitStrategy:通过线程阻塞的方式,等待生产者唤醒,被唤醒后,再循环检查依赖的sequence是否已经消费
    • BusySpinWaitStrategy:线程一直自旋等待,可能比较耗CPU
    • LiteBlockingWaitStrategy:线程阻塞等待生产者唤醒,与BlockingWaitStrategy相比,区别在signalNeeded.getAndSet,如果两个线程同时访问,一个访问waitfor,一个访问signalAll时,可以减少lock加锁次数
    • LiteTimeoutBlockingWaitStrategy:与LiteBlockingWaitStrategy相比,设置了阻塞时间,超过时间后抛异常
    • PhasedBackoffWaitStrategy:根据时间参数和传入的等待策略来决定使用哪种等待策略
    • TimeoutBlockingWaitStrategy:相对于BlockingWaitStrategy来说,设置了等待时间,超过后抛异常
    • YieldingWaitStrategy:尝试100次,然后Thread.yield()让出CPU
    • SleepingWaitStrategy:sleep
  • 消费者异常处理
    • 默认:disruptor.setDefaultExceptionHandler()
    • 覆盖:disruptor.handleExceptonFor().with()
 
 
 
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值