线程

  1. 进程和线程的区别

    1. 操作系统以进程为单位,分配 cpu 资源,进程是资源分配的最小单位
    2. 线程是轻量级进程,是操作系统调度执行的最小单位
    3. 线程可以共享进程内资源,进程资源是独立的
    4. 进程间通信
      • 管道
      • 信号
      • 消息队列
      • 共享内存
      • 信号量
      • 套接字
  1. 操作系统中的线程

    1. 线程间会有同步互斥

      同步互斥控制方法

      • 临界值
      • 互斥量
      • 信号量
      • 事件
    2. 上下文切换

      1. 指 CPU 从一个进程或线程到另一个线程或进程切换
      2. 只能在内核模式下发生
      3. 是多任务的一个特性
      4. 成本很高
    3. 内核态和用户态

      1. 内核态是完全且不受限制的访问硬件,为操作系统的最低级别
      2. 用户态是不能直接访问硬件或引用内存,需要委托给系统 api 访问。
      3. 系统如何切换为内核态
        1. 系统调用
        2. 异常事件
        3. 设备中断
    4. 操作系统线程生命周期

      1. 初始
      2. 就绪
      3. 运行
      4. 休眠
      5. 终止
    5. java 中线程的生命周期

      1. 初始
      2. 就绪 (可运行与运行)
      3. 阻塞
      4. 等待
      5. 带时间等待
      6. 终止
  2. java 中线程

    1. 线程实现方式
      1. 使用或继承 Thread 类
      2. runnable 接口 —将线程和任务隔离
      3. callable 接口 —可以获取返回值,可以获取异常,一般结合线程池使用
      4. lambda 直接生成
  3. 协程

    1. 基于线程,但比线程更轻量级,不被操作系统内核管理,而完全用程序控制,对于内核有不可见特性。
    2. 协程适用于被阻塞,且需要大量并发场景 (网络 IO),不适合大量计算场景
  4. java 线程的调度机制

    1. 线程调度分别是协同式和抢占式

      1. 协同式是线程执行时间由线程本身决定的,执行完了通知系统切换。
        1. 优点是实现简单,切换操作对线程可知,无线程同步问题。
        2. 缺点是线程执行时间不可控,如出现问题,就可能一直阻塞
      2. 抢占式是有系统分配执行时间,线程切换不由线程本身决定
      3. java 使用的是抢占式,java 共有 **10 种 ** 线程优先级,但不靠谱,线程还是用系统调用的,主要依靠的是操作系统的调用
    2. Thread 常用方法

      1. sleep
        • 会让线程从 Running 进入 TIMED_WAITING,不会释放锁
        • 其他线程可以使用 interrupt 打断睡眠线程,sleep 会抛出 InterruptedException,并且清除中断标志
        • 睡眠结束后线程不一定会立刻执行
        • 如传入时间为 0,则和 yield 相同
      2. yield
        • yield 会释放 cpu 资源,是线程进入 runnable 状态,让优先级更高的线程获得执行机会,不会释放锁
        • main 调用只会继续执行,因为 main 优先级最高
        • 具体实现依赖于操作系统的任务调度
      3. join
        • 让主线程 waiting,一直等到其他线程不再活动为止
      4. stop
        • 会停掉线程同时会释放锁,不推荐,会导致线程不安全
    3. java 中断机制停止线程

      1. 中断是一种协作机制,即通过中断并不能直接终止另一个线程,而是由被中断的线程自己处理是否中断。
      2. API 的使用
        1. interrupt,将线程的中断标志设置为 true,不会停止线程
        2. isInterrupt,判断当前线程中断标志是否为 true,不会清除中断标志
        3. Thread.interrupted(),判断当前线程中断标志位是否为 true,并清除中断标志,重置为 false
        4. sleep 和 wait 也会清除中断标记,如果需要使用中断机制,每次 catch 中都需要将中断标志补回为 true
    4. java 的线程间的通信

      1. volatile 关键字

      2. 等待唤醒机制

        1. 可以基于 wait 和 notify 进行实现

          1. 缺点一,必须在 synchronized 中执行,依靠的锁
          2. 缺点二,多线程等待,不一定唤醒指定线程,即使用 notifyAll 去唤醒全部线程,也是让其他线程去抢占
        2. 也可以通过

          LockSupport

          ,它是 JDK 用于实现线程阻塞和唤醒的工具,线程调用 park 则等待“许可”,调用 unpark 则指定线程提供“许可“。

          1. 通常使用这个方法
      3. 管道输入输出流

      4. join

细节点

  • Linux 没有线程,后续单独写了一套,又称轻量级进程。
  • nginx 是多进程执行的。

进程间的通讯

同一台计算机间的为 IPC

管道机制
  1. 匿名管道:用于父子进程之间的通信
  2. 命名管道:无关系进程间可以通过命名来查询
信号

​ 软件上对中断机制的模拟

消息队列
共享内存

​ 需要考虑同步操作

信号量

套字节 (socket)

​ mysql 使用该种方式,不需要通过网络协议栈,没有打包拆包校验等操作,效率更高

mysql 中 tmp.sock 文件用于创建 socket

不同计算机间为 RPC

如 dubbo 框架、Http 协议也常用于 RPC,如 SpringCloud 微服务

CPU 核心数和线程数

Intel 中引入了逻辑处理器的概念,使核心数和线程数有 1:2 的关系

java 中 Runtime.getRuntime().availableProcessors(),可以获得当前 cpu 核心数(逻辑处理器核心数)

这个和并发编程中设置线程数量关联很大

上下文切换

上下文就代表不同线程或者进程的数据,在 cpu 切换的时候,需要将这种数据(可理解为局部变量)存入内存中