线程与线程池

# 线程的优先级

不同操作系统的线程优先级规划存在差异, 甚至会忽略线程优先级设定.

    Thread thread = new Thread(() -> {...});
    // 默认优先级为5
    thread.setPriority(1到10)
1
2
3

# 线程状态

  • new 线程创建尚未运行, 处于就绪状态
  • run 运行状态.

java将操作系统中的运行和就绪统称为运行状态

  • blocked 阻塞状态
  • waiting 等待状态
  • waiting_time 超时等待状态
  • terminated 结束

# 中断

thread.interrupt()方法会中断目标线程, 但中断不等于使目标线程立刻结束, 而是设置一个标记, 当在线程处于阻塞状态时, 如果检查到线程的阻塞标记为true时, 将会抛出InterruptedException, 线程在抛出InterruptedException之前会先将中断标志清除.

thread.isInterrupted()方法目标线程的中断标记

Thread.interrupted()可以返回当前线程的中断标记, 并对当前线程的中断标志复位.

# join

thread.join()方法会使当前线程等待目标线程终止才会从join方法返回

# Daemon线程

在线程运行之前, setDaemon将线程设置为守护线程, 守护线程在虚拟机退出时会自动退出, 守护线程的finally块代码不一定执行.

# 线程池大小

线程池数量过大会带来大量不必要的线程上下文切换开销.

线程池的理想大小取决于任务的类型以及所部署系统的特性. 对于计算密集型任务, 线程池大小为CPU +1 利用率为最佳.

对于包含IO操作或其他阻塞操作的任务, 线程池大小 = cpu数量 * (线程等待时间(非cpu运行时间, 如IO)与线程cpu运行时间之比 + 1), 也就是线程等待时间所占的比例越高, 所需要的线程数量越多. 线程CPU运行时间所占比例越高, 所需要的线程数量越少.

# 线程池的任务队列

当线程池被所有线程都在被使用时, 新提交的任务将添加到任务队列中等待稍后执行

  • 有界队列.
  • 无界队列. newFixedThreadPool和newSingleThreadPool默认使用一个无界队列LinkedBlockingQueue
  • 同步移交. SynchronousQueue不是一个真正的队列. 而是一种在线程之间一脚的机制, 任务将直接提交给线程, 只有线程池时无界的或者有拒绝策略时, 才有实际价值.

# 线程池的饱和策略

当线程池的任务队列满时, 再次添加新的任务会触发线程池的饱和策略.

  • AbortPolicy. 默认的饱和策略, 会抛出一个RejectedException.
  • CallerRunsPolicy. 不会抛弃任务, 也不会抛出异常, 而是将任务回退给调用者, 谁调用了execute, 任务就退还给谁来执行.
  • DiscardPolicy. 当新提交的任务无法保存到队列中时, 会悄悄抛弃掉该任务
  • DiscardOldestPolicy. 抛弃下一个将被执行的任务, 然后重新提交新任务, 最好不要和优先级队列一起使用

当没有预定义的饱和策略时, 可以使用信号量来控制任务的提交速率, 信号量大小为线程池大小及可排队任务的数量

上次更新: 2022/3/11 15:12:48