线程

进程是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。
线程是调度 CPU 的最小单元,也叫轻量级进程 LWP(Light Weight Process)。

状态

线程 - 图1
new,ready,running,waiting,blocked,terminated

线程模型

  • 用户级线程(ULT)
    • 用户程序实现,不依赖操作系统核心,应用提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态 / 内核态切换,速度快。内核对 ULT 无感知,线程阻塞则进程(包括它的所有线程)阻塞。
  • 内核级线程(KLT)
    • 系统内核管理线程(KLT),内核保存线程的状态和上下文信息,线程阻塞不会引起进程阻塞。在多处理器系统上,多线程在多处理器上并行运行。线程的创建、调度和管理由内核完成,效率比 ULT 要慢,比进程操作快。(JVM 大多使用 KLT)

image.png

Java 线程与系统内核线程

Java 线程创建是依赖于系统内核,通过 JVM 调用系统库创建内核线程,内核线程与 Java-Thread是 1::1 的映射关系。
image.png

线程池

池化思想:线程池、字符串常量池、数据库连接池
目的:提高资源的利用率

  1. 手动创建线程对象
  2. 执行任务
  3. 执行完毕,释放线程

    优点

  • 重用存在的线程,减少线程创建,消亡的开销,提高性能
  • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • 提高线程的可管理性,可统一分配,调优和监控。

    意义

    线程是稀缺资源,它的创建与销毁是一个相对偏重且耗资源的操作,而 Java 线程依赖于内核线程,,创建线程需要进行操作系统状态切换,为避免资源过度消耗需要设法重用线程执行多个任务。线程池就是一个线程缓存,负责对线程进行统一分配、调度与监控。

    什么时候使用?

  • 单个任务处理时间比较短

  • 需要处理的任务数量很大

    阻塞队列

  1. 在任意时刻,不管并发有多高,永远只有一个线程能够进行队列的入队或者出队的操作!
  2. 线程安全
  3. 有界 || 无界
  4. 队列满,只能进行出队操作,所有入队的操作必须等待,也就是被阻塞
  5. 队列空,只能进行入队操作,所有出队的操作必须等待,也就是被阻塞

    自定义线程池

    1. public class MyThreadPool {
    2. public static void main(String[] args) {
    3. /**
    4. * public ThreadPoolExecutor(int corePoolSize, //核心线程池的大小
    5. * int maximumPoolSize, //最多线程数
    6. * long keepAliveTime, // 线程没有工作,最大存活时间
    7. * TimeUnit unit, //时间单位
    8. * BlockingQueue<Runnable> workQueue, //负荷状态下的阻塞队列
    9. * ThreadFactory threadFactory,
    10. * RejectedExecutionHandler handler)
    11. */
    12. ExecutorService service = new ThreadPoolExecutor(3, 5, 1L, TimeUnit.SECONDS,
    13. new ArrayBlockingQueue<>(3),
    14. Executors.defaultThreadFactory(),
    15. new ThreadPoolExecutor.AbortPolicy());
    16. for (int i = 0; i < 9; i++) {
    17. service.execute(() -> {
    18. System.out.println(Thread.currentThread().getName() + " ====> " + "正在办理业务");
    19. });
    20. }
    21. service.shutdown();
    22. }
    23. }

    image.png

    状态

    Running

    能接受任务以及处理已添加的任务

    ShutDown

    不接受新任务,可以处理已经添加的任务

    Stop

    不接受新任务,不处理已经添加的任务,并且中断正在处理的任务

    Tidying

    所有的任务已经终止,ctl 记录的 “任务数量”为 0,ctl 负责记录线程池的运行状态与活动线程数量

    Terminated

    线程池彻底终止,则线程池转变为 terminated 状态
    image.png ```java private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3; //用高3位记录线程状态 //低29位记录当前工作线程数 private static final int CAPACITY = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;

// Packing and unpacking ctl private static int runStateOf(int c) { return c & ~CAPACITY; } private static int workerCountOf(int c) { return c & CAPACITY; } private static int ctlOf(int rs, int wc) { return rs | wc; } ``` image.png