Java多线程与高并发琐事

多线程

进程

  • 进程同步机制

    • 共享内存
    • 信号量
    • 管道
    • 消息队列
    • 套接字
  • 进程的状态和转换

    • 运行、就绪、等待
  • 守护进程

    • 守护进程就是在后台运行,不与任何终端关联的进程,
      通常情况下守护进程在系统启动时就在运行,
      它们以root用户或者其他特殊用户(apache和
      postfix)运行,并能处理一些系统级的任务.
  • 孤儿进程

    • 如果父进程先退出,子进程还没退出那么子进程将被 托孤给init进程
  • 僵尸进程

    • 一个进程已经终止了,但是其父进程还没有获取其状态

    • 如何避免

      • 在父进程创建子进程之前,就向系统申明自己并不会对这个子进程的
        exit动作进行任何关注行为,这样的话,子进程一旦退出后,系统就
        不会去等待父进程的操作,而是直接将该子进程的资源回收掉,也就
        不会出现僵尸进程了
      • fork两次,父进程fork一个子进程,然后继续工作,
        子进程fork一个孙进程后退出,那么孙进程被init接管,
        孙进程结束后,init会回收。不过子进程的回收还要自己做。
      • 父进程通过wait和waitpid等函数等待子进程结束,
        这会导致父进程挂起。

线程

  • 创建线程的方式

    • runnable

    • callable

      • future
      • future task
      • Callable接口的任务线程能返回执行结果
    • Thread

    • 一个类可以同时继承Thread和实现Runnable接口

    • 实现Callable接口的任务线程能返回执行结果;
      而实现Runnable接口的任务线程不能返回结果

    • future的底层实现异步原理

      • 提供了三种功能

        • 判断任务是否完成
        • 能够中断任务
        • 能够获取任务执行结果
      • future的底层实现异步原理

        • 在客户端请求的时候,直接返回客户端需要的数据
          (此数据不一定完整,只是简单的一点不耗时的操作),
          但是客户端并不一定马上使用所有的信息,此时就有了
          时间去完善客户需要的信息
      • 与FutureTask的区别和联系

        • future是个接口,futuretask可以通过实现该接口,
          调用get方法返回执行结果
  • 守护线程

    • 守护线程通常执行一些任务,当所有非守护线程终止的时候,J
      VM简单的丢弃掉所有现存的守护线程.一旦其它非守护线程执
      行完,不一定所有的守护线程都会执行完才退出,它们可能在非
      守护线程执行完后的某个时刻退出

    • 使用场景

      • 来为其它线程提供服务支持.
  • 线程上下文切换

  • 线程的状态

    • 创建、就绪、运行、阻塞、死亡
  • 线程调度器

    • 负责为runnable状态线程分配cpu时间
  • 线程同步机制

    • 临界区

      • 指的是一个访问共用资源(例如:共用设备或是共用存储器)
        的程序片段,而这些共用资源又无法同时被多个线程访问的特性
    • 互斥量

    • 信号量

      • volatile
    • 事件

      • 选择器epoll()

线程池

  • 管理一组工作线程

  • 等待执行任务的消息队列

  • 创建线程池的方式

    • 创建线程池

      • newSingleThreadExecutor(单线程线程池)

        • 适用场景

          • 适用于串行执行任务的场景
      • newFixedThreadPool(固定大小线程池)

        • 特点

          • coresize和maxsize相同
          • 队列用的LinkedBlockingQueue无界
          • keepAliveTime为0
        • 工作机制

          • 1.线程数少于核心线程数,新建线程执行任务
          • 2.线程数等于核心线程数后,将任务加入阻塞队列
          • 3.执行完任务的线程反复去队列中取任务执行
        • 适用场景

          • 适用于处理CPU密集型的任务,
            确保CPU在长期被工作线程使用的情况下,
            尽可能的少的分配线程即可。一般Ncpu+1
      • newCachedThreadPool(可缓存线程的线程池)

        • 特点

          • 核心线程数为0,且最大线程数为Integer.MAX_VALUE
          • 阻塞队列是SynchronousQueue
          • keepAliveTime为60s
        • 工作机制

          • 1.没有核心线程,直接向SynchronousQueue中提交任务
          • 2如果有空闲线程,就去取出任务执行;
            如果没有空闲线程,就新建一个
          • 3.执行完任务的线程有60秒生存时间,
            如果在这个时间内可以接到新任务,
            就继续,否则结束生命
        • 适用场景

          • 用于并发执行大量短期的小任务
      • newScheduledThreadPool

        • 特点

          • 最大线程数为Integer.MAX_VALUE
          • 阻塞队列是DelayedWorkQueue
        • 工作机制

          • 1.线程从 DelayQueue 中获取 time 大于等于当前时间的 
            ScheduledFutureTask(DelayQueue.take())
          • 2.执行完后修改这个 task 的 time 为下次被执行的时间
          • 3.再把这个 task 放回队列中
        • 适用场景

          • 用于需要多个后台线程执行周期任务,
            同时需要限制线程数量的场景。
    • 两种启动线程池的方法:submit(有返回值)和execute(无返回值)

    • 线程池的核心

      • 生产者消费者模型

        • 生产者将需要处理的任务放入队列
        • 消费者从任务队列中取出任务处理
    • 线程池的参数(ThreadPoolExecutor)

      • maximumPoolSize:最大线程数

      • corePollSize:核心线程数

      • keepAliveTime:空闲的线程保留的时间

      • workQueue任务队列):
        用于保存等待执行的任务的阻塞队列

      • ThreadFactory

        • 用于设置创建线程的工厂,可以通过线程工厂给每个
          创建出来的线程做些更有意义的事情,比如设置daemon和优先级等等
      • RejectedExecutionHandler(饱和策略)

        • AbortPolicy:直接抛出异常。
        • CallerRunsPolicy:只用调用者所在线程来运行任务。
        • DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
        • DiscardPolicy:不处理,丢弃掉。
      • TimeUnit:空闲线程的保留时间单位

  • 单机上一个线程正在处理服务,如果忽然断电了怎么办
    (正在处理和阻塞队列里的请求怎么处理)

    • 阻塞队列持久化,正在处理事物控制。断电之后正在处理的回滚,
      日志恢复该次操作。服务器重启后阻塞队列中的数据再加载
  • 线程池关闭相关操作

    • shutdown

      • shutdown()后线程池将变成shutdown状态,此时不接收新任务,
        但会处理完正在运行的 和 在阻塞队列中等待处理的任务。
    • shutdownNow

      • shutdownNow()后线程池将变成stop状态,此时不接收新任务,
        不再处理在阻塞队列中等待的任务,还会尝试中断正在处理中的工作线程。

阻塞队列

  • 支持两个附加操作

    • 当队列满时,存储元素的线程会等待队列可用
    • 当队列空时,获取元素的线程会等待队列变为非空
  • 阻塞队列先设定大小,防止内存溢出

  • 线程池队列

    • ArrayBlockingQueue(有界队列)

      • 是一个基于数组结构的有界阻塞队列,
        此队列按 FIFO(先进先出)原则对元素进行排序
      • 可以指定缓存队列的大小,当正在执行的线程数等于corePoolSize时,多余的
        元素缓存在ArrayBlockingQueue队列中等待有空闲的线程时继续执行,当
        ArrayBlockingQueue已满时,加入ArrayBlockingQueue失败,会开启新的
        线程去执行,当线程数已经达到最大的maximumPoolSizes时,再有新的元素
        尝试加入ArrayBlockingQueue时会报错
    • LinkedBlockingQueue(无界队列)

      • 一个基于链表结构的阻塞队列,此队列按FIFO (先进先出)
        排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法
        Executors.newFixedThreadPool()使用了这个队列。

      • maximumPoolSizes为无效

        • 当前执行的线程数量达到corePoolSize的数量时,
          剩余的元素会在阻塞队列里等待
    • SynchronousQueue(同步队列)

      • 一个不存储元素的阻塞队列。每个插入操作必须等到
        另一个线程调用移除操作,否则插入操作一直处于阻塞状态,
        吞吐量通常要高于LinkedBlockingQueue,静态工厂方法
        Executors.newCachedThreadPool使用了这个队列。

      • maximumPoolSizes为无界

        • 使用SynchronousQueue阻塞队列一般要求
          maximumPoolSizes为无界,避免线程拒绝执行操作
      • 特点

        • SynchronousQueue 队列中没有任何缓存的数据,
          可以理解为容量为 0
        • SynchronousQueue 提供两种实现方式,
          分别是 栈 和 队列 的方式实现。这两种实现方式中,
          栈 是属于非公平的策略,队列 是属于公平策略
    • DelayQueue(延迟队列)

      •  一个任务定时周期的延迟执行的队列。
        根据指定的执行时间从小到大排序,
         否则根据插入到队列的先后排序。
    • PriorityBlockingQueue(优先级队列)

      • 一个具有优先级得无限阻塞队列
    • LinkedTransferQueue

判断线程是否停止的方法interrupted

和isinterrupted的区别

  • interrupted

    • 静态方法
    • 作用于当前正在运行的线程
    • 会清除线程中断状态
  • isinterrupted

    • 非静态方法
    • 作用于该方法的调用对象所对应的线程

三个线程交替顺序打印ABC

  • 使用synchronized, wait和notifyAll
  • 使用Lock->ReentrantLock 和 state标志
  • 使用Lock->ReentrantLock 和
    Condition(await 、signal、signalAll)
  • 使用Semaphore
  • 使用AtomicInteger

多线程中join()方法

  • t.join()方法只会使主线程进入等待池并等待t线程
    执行完毕后才会被唤醒。并不影响同一时刻处在
    运行状态的其他线程

缓存一致性问题

  • 加lock锁
  • 缓存一致性协议

ThreadLocal

  • 相当于一个容器,用于存放每个线程的局部变量
  • 底层也是封装了ThreadLocalMap集合类来绑定当
    前线程和变量副本的关系,各个线程独立并且访问安全

run和start

死锁

  • 必要条件

    • 互斥
    • 请求和保持
    • 循环等待
    • 不可剥夺
  • 防止死锁

    • 预防
    • 避免
    • 检测
    • 解除

锁优化

  • 减少锁的持有时间

  • 减少锁得用于粒度

  • 锁分离

    • 读锁
    • 写锁
  • 锁粗化

    • 如果一段程序要多次请求锁,锁之间的代码执行时间比较少,就应该整合成一个锁
  • 自旋锁(不可重入锁)

  • 锁清除

    • 堆检测到不可能存在共享数据竞争的锁进行清除(逃逸分析技术)
  • 锁降级

    • 指的是把持住(当前拥有的)写锁,再获取到读锁,随后释放(先前有用的)写锁的过程

volatile

  • 可见性

    • 底层是共享变量
  • 禁止重排序

    • 内存屏障

      • LoadLoad
      • StoreStore
      • LoadStore
      • StoreLoad
  • 内部实现机制

    • 将当前内核高速缓存行的数据立刻回写到内存
    • 使在其他内核里缓存了该内存地址的数据无效
    • MESI协议,该解决缓存一致性的思路是:当CPU写数据时,如果发现操作的变量是共享
      变量,即在其他CPU中也存在该变量的副本,那么他会发出信号通知其他CPU将该变量
      的缓存行设置为无效状态。当其他CPU使用这个变量时,首先会去嗅探是否有对该变量更
      改的信号,当发现这个变量的缓存行已经无效时,会从新从内存中读取这个变量。
  • 内存语义

    • 内存可⻅性

      • 具有与锁相同的内存主题,轻量级锁

        • volatile仅仅保证对单个volatile变量的读/写具有原⼦
        • 锁可以保证整个临界区代码的执⾏具有原⼦性
        • 在功能上,锁⽐
          volatile更强⼤;在性能上,volatile更有优势
    • 禁⽌重排序

      • 双重锁检查的单例模式

      • JSR-133增强:严格限制编译器和处理器对volatile变量与普通变量的重排序

        • 禁止编译器重排序

          • 在每个volatile写操作前插⼊⼀个StoreStore屏障
          • 在每个volatile写操作后插⼊⼀个StoreLoad屏障
          • 在每个volatile读操作后插⼊⼀个LoadLoad屏障
          • 在每个volatile读操作后再插⼊⼀个LoadStore屏障
        • 禁止处理器重排序

          • 内存屏障

            • 读屏障(Load Barrier)

            • 写屏障
              (Store Barrier)

            • 作用

              • 阻⽌屏障两侧的指令重排序
              • 强制把写缓冲区/⾼速缓存中的脏数据等写回主内存,或者让缓存中相应的数据
                失效,这里的缓存指CPU缓存L1,L2
        • volatile变量与普通变量的访问规则

          • 子主题 1

用户态和核心态

无锁化编程实现线程安全

  • final(数据不可修改)
  • CAS
  • ThreadLocal

读写锁

  • 写独占,读共享,CopyOnWriteArrayList(非公平锁)

如何判断一个线程是否拥有锁

  • Thread的holdsLock方法

happens-before原则

  • 如果前一个操作(A)必须要对后一个操作(C)可见 ,那么这两个操作(A C) 指令不能重排

乐观锁(适用于大并发量)

  • CAS

    • Unsafe

    • 不同的操作系统和处理器的实现
      会有所不同

    • 怎样使用:java.util.concurrent.atomic 原子操作类

      • do-while循环保证循环体至少执行一遍
    • 问题

      • ABA问题

        • 版本号或者时间戳
        • JDK1.5提供的AtomicStampedReference
      • 循环时间⻓开销⼤

        • 让JVM⽀持处理器提供的pause指令

          pause指令能让⾃旋失败时cpu睡眠⼀⼩段时间再继续⾃旋,从⽽使得读操作的频
          率低很多,为解决内存顺序冲突⽽导致的CPU流⽔线重排的代价也会⼩很多

      • 只能保证⼀个共享变量的原⼦操作

        • JDK1.5的AtomicReference

悲观锁(适用于并发量不大的场景)

  • Lock

    • 悲观锁、可中断锁、可公平锁、可重入锁)
  • synchronized

    • 悲观锁、不可中断锁、非公平锁、可重入锁)
    • 底层通过操作系统的互斥量实现,适用于竞争不激烈的场景

可重入锁和不可重入锁(自旋锁)

  • 可重入锁实现原理:当一个线程请求成功后,JVM会记下持有锁的线程,
    并将计数器计为1。此时其他线程请求该锁,则必须等待;
    而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增

synchronized 和 volatile 的区别是什么?

  • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,
    需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以
    访问该变量,其他线程被阻塞住
  • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
  • volatile仅能实现变量的修改可见性,不能保证原子性;
    而synchronized则可以保证变量的修改可见性和原子性
  • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞
  • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

synchronized 和 ReentrantLock 区别是什么

  • synchronized是关键字、ReentrantLock是类

    • ReentrantLock是类,那么它就提供了比synchronized更多更灵活的特性,
      可以被继承、可以有方法、可以有各种各样的类变
  • ReentrantLock可以对获取锁的等待时间进行设置

  • ReentrantLock可以获取各种锁的信息

  • sychronized是不可中断锁、非公平锁;ReentrantLock是可中断,可公平锁

  • ReentrantLock需在finally中手工释放锁

高并发系统限流中的算法

  • 漏桶算法

    • 一个固定容量的漏桶,按照固定常量速率流出请求,
      流入请求速率任意,当流入的请求数累积到漏桶容量时,
      则新流入的请求被拒绝
  • 令牌桶算法

    • 一个存放固定容量令牌的桶,按照固定速率往桶里添加令牌,
      填满了就丢弃令牌,请求是否被处理要看桶中令牌是否足够,
      当令牌数减为零时则拒绝新的请求
  • 计数器限流算法

    • 用来限制一定时间内的总并发数,
      比如数据库连接池、线程池、秒杀的并发数

锁的状态

  • 无锁状态

  • 偏向锁状态

    • 偏向锁是指一段同步代码一直被一个线程所访问,
      那么该线程会自动获取锁。降低获取锁的代价。
  • 轻量级锁状态

    • 轻量级锁是指当锁是偏向锁的时候,被另一个线程
      所访问,偏向锁就会升级为轻量级锁,其他线程会
      通过自旋的形式尝试获取锁,不会阻塞,提高性能。
  • 重量级锁状态

    • 重量级锁是指当锁为轻量级锁的时候,另一个线程虽然是自旋,
      但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,
      就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线
      程进入阻塞,性能降低。

自旋锁与非自旋锁

  • 自旋锁

    • 一直循环尝试获取锁
  • 非自旋锁

    • 阻塞等待
  • 公平

    • 公平的自旋锁

      • https://blog.csdn.net/qq_34337272/article/details/81252853?utm_source=app
  • 可重入

    • 可重入的自旋锁

      • https://blog.csdn.net/qq_34337272/article/details/81252853?utm_source=app

Thread类和Runnable接⼝

  • 实现线程

    • 继承 Thread 类,并重写 run ⽅法
    • 实现 Runnable 接⼝的 run ⽅法
  • Thread类的⼏个常⽤⽅法

    • currentThread()

    • start()

    • yield()

      当前线程调⽤了yield()⽅法,程序在调度的时候,也还有可能继续运⾏这个线程的

    • sleep(),睡眠一段时间

    • join()

      使当前线程等待另⼀个线程执⾏完毕之后再继续执⾏,内部调⽤的是Object类的wait⽅法实现的

wait、notify、notifyall

  • 只能由获取对象监视器的线程调用,否则抛出异常IllegalMonitorStateException
  • Object类的方法

wait、sleep

  • wait

    • 阻塞线程并且释放锁
    • Object类
  • sleep

    • 阻塞线程但不释放锁
    • Thread类

锁接口与类

  • synchronized的不⾜之处

    • 如果临界区是只读操作,其实可以多线程⼀起执⾏,但使⽤synchronized的
      话,同⼀时间只能有⼀个线程执⾏
    • synchronized⽆法知道线程有没有成功获取到锁
    • 使⽤synchronized,如果临界区因为IO或者sleep⽅法等原因阻塞了,⽽当前
      线程⼜没有释放锁,就会导致所有线程等待
  • 锁的分类

    • 可重⼊锁和⾮可重⼊锁

      • synchronized是可重⼊锁
      • 继承AQS类时考虑是否可重入
      • ReentrantLock是可重入锁
    • 公平锁与⾮公平锁

      • 先来后到
      • ⾮公平锁能提升⼀定的效率。但是⾮公平锁可能会发⽣线程饥饿(有
        ⼀些线程⻓时间得不到锁
      • ReentrantLock⽀持⾮公平锁和公平锁两种
    • 读写锁和排它锁

      • 排它锁在同⼀时刻只允许⼀个线程进⾏访问

        • synchronized锁和ReentrantLock都是排它锁
      • 读写锁可以在同⼀时刻允许多个读线程访问

        • ReentrantReadWriteLock
  • java.util.concurrent.locks包

    • 抽象类AQS/AQLS/AOS

    • 接⼝Condition/Lock/ReadWriteLock

      • Condition

        • Object 的wait/notify⽅法来实现等待/通
          知机制

        • 与Lock配合来
          实现等待/通知机制

        • 两者对比

          • Condition的await⽅法对应的是
            Object的wait⽅法,⽽Condition的signal/signalAll⽅法则对应Object的
            notify/notifyAll()
    • ReentrantLock

      • Lock接口实现
    • ReentrantReadWriteLock

      • ReadWriteLock接口实现
      • 缺点:在“写”操作的时
        候,其它线程不能写也不能读,称为“写饥饿”
    • StampedLock

      • 锁中的性能之王

      • 实现读写锁的功能

      • 读锁

        • 乐观读锁
        • 悲观读锁
      • 不会发生写饥饿

        在读的时候如果发⽣了写,应该通过
        重试的⽅式来获取新的值,⽽不应该阻塞写操作。这种模式也就是典型的⽆锁编程
        思想,和CAS⾃旋的思想⼀样

      • 取代ReentrantReadWriteLock

线程池

  • 使用原因

    • 复用线程
    • 控制并发
    • 统⼀管理
  • Executor 顶层接⼝

    • ThreadPoolExecutor实现类

      • 四个构造函数

      • 7个参数

        • corePoolSize

          • 核心线程数(铁饭碗)
        • maximumPoolSize

          • 最大线程数(核心+非核心)
        • keepAliveTime

          • ⾮核⼼线程闲置超时时⻓,allowCoreThreadTimeOut(true)会作用于核心线程
        • unit

          • keepAliveTime的单位
        • workQueue

          • Runnable类型的阻塞队列
        • threadFactory

          • 创建线程的⼯⼚,设置线程的参数
        • handler

          • 拒绝处理策略

          • 线程数量⼤于最⼤线程数就会采⽤拒绝处理策略

          • 4种实现

            • ThreadPoolExecutor.AbortPolicy:默认拒绝处理策略,丢弃任务并抛出RejectedExecutionException异常
            • ThreadPoolExecutor.DiscardPolicy:丢弃新来的任务,但是不抛出异常
            • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列头部(最旧的)的任务,然后重新尝试执⾏程序(如果再次失败,重复此过程)
            • ThreadPoolExecutor.CallerRunsPolicy:由调⽤线程处理该任务
      • execute处理流程

      • 线程复用原理

    • ExecutorService子接口

      • AbstractExecutorService抽象实现类,实现了ExecutorService子接口的全部方法,子类只要重写Excutor的execute方法即可
      • 线程池的相关操作
    • void execute(Runnable command)方法

  • Executors 类创建线程池

  • 建议

    • 参考阿里巴巴Java开发手册

同步容器与并发容器

  • 区别:同步容器存在线程安全的复合操作问题

  • 并发Map

    • ConcurrentMap接⼝

      • ConcurrentHashMap类
    • ConcurrentNavigableMap接⼝

      • ConcurrentSkipListMap类
  • 并发Queue

    • ConcurrentLinkedDeque
    • ConcurrentLinkedQueue
  • 并发Set

    • ConcurrentSkipListSet

      • 线程安全的有序集合。底层ConcurrentSkipListMap
    • 谷歌guava

      • ConcurrentHashSet
      • Set s = Sets.newConcurrentHashSet();
    • CopyOnWriteArraySet

  • 并发List

    • CopyOnWriteArrayList

      • 用例:定时黑名单刷新
      • 最终一致性
    • CopyOnWriteArrayList

通信⼯具类

  • Semaphore

    • 限制线程的数量
  • Exchanger

    • 两个线程交换数据

      • exchange(V x)
      • exchange(V x, long timeout, TimeUnit unit)
  • CountDownLatch

    • 线程等待直到计数器减为0时开始⼯作

    • 公共方法

      // 构造⽅法:
      public CountDownLatch(int count)
      //等待
      public void await()
      public boolean await(long timeout, TimeUnit unit) // 超时等待
      public void countDown() // count - 1
      public long getCount() // 获取当前还有多少count

    • 用例:游戏开始之前的前置任务

      • 加载地图数据
      • 加载⼈物模型
      • 加载背景⾳乐
    • 缺点:不能重新计算计数值,只能起到一次屏障的作用

  • CyclicBarrier

    • 作⽤跟CountDownLatch类似,但是可以重复使⽤
    • 异常处理机制
    • https://juejin.im/post/5b6fce4be51d45664c239f14
  • Phaser

    • 增强的CyclicBarrier
    • 可忽略

Callable、Future与FutureTask

  • Callable接⼝

    • 与Runnable相比,有返回值
    • 函数式接口
  • Future接口

    • 顶层接口

    • ExecutorService的三个submit方法的返回值

      • Future submit(Callable task)
      • Future submit(Runnable task, T result)
      • Future<?> submit(Runnable task)
    • cancel方法可以取消线程的执行,不一定成功

  • FutureTask类

    • ExecutorService的三个submit方法的Future接口实现类

死锁

  • 故事:哲学家进餐问题

  • 有向图

    • 节点为线程,边为线程等待对方线程占有的资源
    • 形成环路产生死锁
  • 锁顺序死锁

    • 获取锁方向不同
    • 有A想B,有B想A

计划任务

  • ScheduledThreadPoolExecutor

    • 阻塞队列:DelayedWorkQueue

      • 队头是最近将要执⾏的任务
      • 优先队列,底层是数组堆
      • 因为有出入队的调整,定时不是十分准确
    • 构造方法调用父类

    • 实现ScheduledExecutorService接口

      • schedule

        • 单次任务
      • schedule

        • 单次任务
      • scheduleAtFixedRate

        • 第一次任务延迟,每隔一段时间,前面任务未完成则等待
      • scheduleWithFixedDelay

        • 第一次任务延迟,每次完成任务等待delay再运行
    • 执行原理

      • 包装任务:RunnableScheduledFuture
      • 调用void delayedExecute(RunnableScheduledFuture<?> task)
  • Timer

AQS

  • 抽象队列同步器

    • ReentrantLock
    • ReentrantReadWriteLock
    • Semaphore
    • FutureTask
    • SynchronousQueue
  • 数据结构

    • FIFO队列
  • 资源共享模式

    • 独占模式

      • ReentrantLock
    • 共享模式

      • Semaphore/CountDownLatch
    • 使用

      • 选择其中一种模式
      • 两种模式共用,如ReadWriteLock
    • 内部类Node

      注意:通过Node我们可以实现两个队列,⼀是通过prev和next实现CLH队列,⼆是nextWaiter实现Condition条件上的等待线程队列(单向队列),这个Condition主要⽤在ReentrantLock类中

    • 内部类ConditionObject

  • AQS的主要⽅法解析

    • protected方法

      • boolean tryAcquire(int)

      • boolean tryRelease(int)

      • int tryAcquireShared(int)

      • boolean tryReleaseShared(int)

      • boolean isHeldExclusively()

        • 该线程是否正在独占资源。只有⽤到condition才需要去
          实现它
      • volatile类型变量state

        • getState
        • setState
        • compareAndSetState
    • public方法

      • void acquire(int)
      • void acquireInterruptibly(int)
      • void acquireShared(int)
      • void acquireSharedInterruptibly(int)
      • boolean tryAcquireNanos(int,long)
      • boolean tryAcquireSharedNanos(int, long)
      • boolean release(int)
      • boolean releaseShared(int)

线程间通信方式

  • 共享变量

  • Object

    • wait
    • notify
    • notifyall
  • Condition

    • await
    • signal
    • signalall
  • LockSupport

等待通知

  • 含义:A线程等待,B线程通知

  • 实现

    • 自旋

    • Object

      • wait
      • notify
      • notifyall
    • Condition接口

      Object实现的等待通知只能在synchronized中使用,当使用Lock显式锁就不能使用了,而Condition就是解决这个问题的

      • 实现

        • AQS中ConditionObject实现类,底层调用LockSupport

          • await前会释放锁
      • 功能

        • 分组唤醒
  • 介绍:https://www.cnblogs.com/sheeva/p/6484224.html

线程状态

  • 操作系统线程状态

    • new
    • ready
    • running
    • waiting
    • terminated
  • Java线程状态(Thread.State)

    • NEW

    • RUNNABLE

      • 操作系统线程的ready+running
    • BLOCKED

      • 正等待锁的释放以进⼊同步区
    • WAITING

      • 方法

        • Object.wait()
        • Thread.join()
        • LockSupport.park()
      • RUNNABLE状态需要其他线程唤醒

    • TIMED_WAITING

      • 线程等待⼀个具体的时间,时间到后会被⾃动唤醒

      • 方法

        • Thread.sleep(long millis)
        • Object.wait(long timeout)
        • Thread.join(long millis)
        • LockSupport.parkNanos(long nanos)
        • LockSupport.parkUntil(long deadline)
    • TERMINATED

XMind - Trial Version

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值