Java并发-线程

线程池原理

线程池是一种池化技术,用于预先创建并管理一组线程,避免频繁创建和销毁线程的开销,提高性能和响应速度。

它的几个关键参数包括:

  • ​ 核心线程数
  • ​ 最大线程数
  • ​ 空闲存活时间
  • ​ 工作队列
  • ​ 拒绝策略

image-20241218173527848

主要工作原理如下:

  • 默认情况下线程不会预创建,任务提交之后才会创建线程(不过设置 prestartAllCoreThreads 可以预创建核心线程)。
  • 当核心线程满了之后不会新建线程,而是把任务堆积到工作队列中。
  • 如果工作队列放不下了,然后才会新增线程,直至达到最大线程数。
  • 如果工作队列满了,然后也已经达到最大线程数了,这时候来任务会执行拒绝策略
  • 如果线程空闲时间超过空闲存活时间,并且线程线程数是大于核心线程数的则会销毁线程,直到线程数等于核心线程数(设置allowCoreThreadTimeOuttrue可以回收核心线程,默认为false)。

创建线程的方式

一般来说,创建线程有很多种方式,例如继承Thread类、实现Runnable接口、使用线程池、使用completableFuture类等等。

不过,这些方式并没有真正创建出线程。准确来说,这些都属于是在Java代码中使用多线程的方式。

严格来说,Java只有一种方式可以创建线程,那就是通过new Thread().start()创建。

不管是哪种方式,最终还是依赖于new Thread().start()

关于这个问题的详细分析可以查看这篇文章:大家都说 Java 有三种创建线程的方式!并发编程中的惊天骗局!

线程的生命周期和状态

Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态:

  • new: 初始状态,线程被创建出来但没有被调用 start()
  • Runnable: 运行状态,线程被调用了 start()等待运行的状态。
  • Blocked:阻塞状态,需要等待锁释放。
  • Watting:等待状态,表示该线程需要等待其他线程做出一些特定动作(通知或中断)。
  • TIME_WAITING:超时等待状态,可以在指定的时间后自行返回而不是像 WAITING 那样一直等待。
  • TERMINATED:终止状态,表示该线程已经运行完毕。

线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换。

创建线程池的方式

创建线程池方式主要有以下三种:

  1. 使用Executos工厂类,例如Executors.newFixedThreadPool(1);

  2. 使用ThreadPoolExcutor直接创建线程池。

    1
    2
    3
    4
    5
    6
    7
    ExecutorService threadPool = new ThreadPoolExecutor(
    5, // corePoolSize
    10, // maximumPoolSize
    60, // keepAliveTime
    TimeUnit.SECONDS, // TimeUnit
    new LinkedBlockingQueue<Runnable>(100) // BlockingQueue
    );
  3. 通过ForkJoinPool创建并行任务线程池。

    1
    2
    3
    4
    ForkJoinPool forkJoinPool = new ForkJoinPool();
    forkJoinPool.submit(() -> {
    // Task
    });