并发1️⃣相关概念、线程状态

前言

并发编程涉及知识点

  1. 进程与线程
  2. 并发与并行
  3. 同步与异步
  4. Java 并发工具、并发问题及解决方案

基础知识

  1. 接触过 Java Web、JDBC 开发、Web 服务器(最好有分布式框架基础)
  2. 基于 JDK 8,了解函数式编程、lambda 表达式
  3. JVM
  4. 日志,方便输出调试

相关日志配置:基于 log4j

  • log4j.properties

    log4j.rootLogger=DEBUG,console
    #控制台输出的相关设置
    log4j.appender.console=org.apache.log4j.ConsoleAppender
    log4j.appender.console.Target=System.out
    log4j.appender.console.Threshold=DEBUG
    log4j.appender.console.layout=org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss:SSS} [%t] - %m%n
    
  • 工具类:debug() 用于输出调试信息。

    public class LogUtils {
        private static final Logger LOGGER = Logger.getLogger(LogUtils.class);
        public static void debug(Object msg) {
            LOGGER.debug(msg);
        }
    }
    

1、初识并发编程

1.1、程序、进程、线程

1.1.1、相关概念

程序(procedure)

  • 程序由指令数据组成,是静态
  • 指令加载到 CPU 才能执行,数据加载到内存才能读写
  • 指令执行过程中需要用到磁盘、网络等设备。

进程(progress)

  • 进程可视为程序的一个实例,是动态(可理解为运行中的程序)。
  • 进程用于加载指令、管理内存和 I/O
  • 当一个指令被执行时,程序从磁盘加载到内存,此时开启了一个进程。
  • 程序可运行一个或多个实例进程(如 QQ音乐、记事本)。

线程(thread)

  • 线程相当于指令流
  • 线程将指令以一定的顺序交给 CPU 执行。

1.1.2、进程 vs 线程

Java 中,进程是资源分配的最小单位,线程是最小调度单位。

  1. 进程基本上相互独立,线程存在于进程内(一个进程由多个线程组成)
  2. 进程拥有共享的资源(如内存空间),供其内部的线程共享。
  3. Windows 中,进程作为线程的容器,自身是不活动的

通信

  • 进程间通信(复杂)
    • 同一台计算机:IPC(Inter-process communication)
    • 不同计算机:通过网络并遵守共同的协议,例如 HTTP
  • 线程通信(简单):线程共享进程的内存(例:多个线程可以访问同一个共享变量)

上下文切换(context switch)

  • 含义:内核在 CPU 上对进程(线程)进行切换,即任务切换。
  • 一般情况下,线程上下文切换成本比进程

1.2、并发、并行

  • 串行(serial):同一时间只能做一件事情(单核 CPU)

  • 并行(parallel):同一时间可以做多件事情(多核 CPU)

    image-20220403150333425

concurrent

单个 CPU 轮流执行线程(线程轮流使用 CPU)

  1. 单核 CPU 下,操作系统的任务调度器,将 CPU 时间片分给不同程序使用。
  2. CPU 在线程间的切换非常快,让人感觉是同时运行的(Windows 时间片最小约 15ms)。
  3. 结论宏观并发,微观串行

parallel

多个 CPU 同时执行多个线程。

  1. 多核 CPU 下,每个 CPU 都可以调度运行线程,线程可以并行执行。
  2. 通常线程数会远大于 CPU 核数,因此并行和并发是同时存在的。
  3. 结论:宏观并行,微观存在串行。

1.3、同步、异步

同步和异步,是基于程序调用方的角度

  • 同步(synchronization):需要等待结果返回才能继续运行。
  • 异步(asynchronization):不需要等待结果返回,就能继续运行。

多线程可以使方法异步执行

  • 开启一个线程用于处理比较耗时的操作,避免阻塞主线程。
  • 应用举例:Tomcat 中的 异步 Servlet、UI 编程中的异步。

2、线程状态

两种说法

  • 操作系统层面:5 种状态
  • Java 层面:6 种状态

2.1、OS:五种状态

操作系统的层面

  1. 初始:创建线程对象实例(属于语言层面),未与操作系统线程关联。

  2. 可运行(就绪):线程已与操作系统相关联,等待 CPU 时间片即可运行。

  3. 运行:线程获取了 CPU 时间片,正在运行。

  4. 阻塞:线程因某种原因而暂停运行(CPU 不会为阻塞线程分配时间片)。

  5. 终止:线程执行完毕,生命周期结束(死亡)。

    image-20220323014842029

2.2、Java:六种状态(!)

Java API 层面来描述

Java Thread 中定义了 State 内部枚举类,包括 6 个线程状态。

  1. NEW:线程对象实例化,但未 start()

  2. RUNNABLE:调用了 start()

    • 线程正在 JVM 中执行。
    • RUNNABLE 涵盖了 OS 层面的 运行、可运行、阻塞(指 BIO 导致的阻塞)
  3. 阻塞状态细分

    • BLOCKED:等待 Monitor 锁(之后会详解)
    • WAITING:无限期等待另一个线程执行完某个特定操作。
    • TIMED_WAITING:在指定等待时间内,等待另一个线程执行完某个特定操作。
  4. TERMINATED:线程代码执行结束(退出)

    image-20220323021543824

posted @ 2022-03-20 15:31  Jaywee  阅读(69)  评论(0编辑  收藏  举报

👇