欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-03 23:37:46
线程的概念、启动方式、常用方法继承Thread实现Runnable接口实现Callable接口synchronized(Object)- 不能用String、常量、Integer、Long- "object"线程同步- synchronized锁的是对象不是代码this、XX.class锁定方法、非锁定方法可同时执行锁升级 - 偏向锁、自旋锁、重量级锁偏向锁:没有......
线程的概念、启动方式、常用方法
  • 继承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()
 
 
 

本文地址:https://blog.csdn.net/ChinaLiaoTian/article/details/109967969