Thread

507 阅读2分钟

Base

  • 进程: 每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)

  • 线程: 同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)

image.png

实现多线程

  • 继承 Thread 类
  • 实现 Runnable 接口

image.png

实现Runnable接口比继承Thread类所具有的优势:

  1. 可以避免java中的单继承的限制

  2. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类

线程池执行任务

image.png

Callable

image.png

Future

image.png

image.png

image.png

image.png

image.png

FutureTask

image.png

image.png

image.png

线程状态

创建、就绪、运行、阻塞、终止。

NewRunnableRunningBlockedDead

image.png

线程安全

image.png

线程池

资源控制,线程管理,避免了线程反复创建销毁所带来的开销问题

  • 反复创建销毁线程,开销大
  • 过多的线程会占用太多内存

参数

image.png

corePoolSize

核心线程数

线程数添加规则:

  • 如果线程数小于corePoolSize, 创建一个核心线程

  • 如果线程数等于或大于corePoolSize, 但小于maxPoolSize, 则将任务放入队列

  • 如果队列已满,并且线程数已满,则创建一个非核心新线程来执行任务

  • 如果队列已满,并且线程数大于或等于maxPoolSize, 则拒绝该任务

判断顺序:corePoolSize > workQueue > maxPoolSize

maxPoolSize

最大线程数

keepAliveTime

多于corePoolSize的线程,超过keepAlveTime, 会被终止

非核心线程的alive time

ThreadFactory

默认使用Executors.defaultThreadFactory()来创建

也可以自定义ThreadFactory,就可以改变线程名,线程组,优先级,是否守护线程

workQueue

直接交接:SynchronousQueue 同步队列

无界队列:LinkedBlockingQueue

有界队列:ArrayBlockingQueue

workStealingQueue (since 1.8)

适合树的遍历,会产生很多子任务去执行

每个线程的子任务会放到自己的队列,其它线程也可以窃取这个队列中的任务,去帮助执行

Handler

拒绝时机

  1. 当Executor关闭时,提交的新任务会被拒绝

  2. 当使用有边界的队列饱和时,会拒绝新提交的任务

RejectPolicy:

  • AbortPolicy -- Default

    抛出异常

  • DiscardPolicy

    直接丢弃

  • DiscardOldestPolicy

    丢弃队列中最老的

  • CallerRunsPolicy

    让调用者跑任务

    优点

    1. 避免了业务损失

    2. 降低提交的速度,相当于一种负反馈,只有在任务执行完毕后,才会继续提交任务,在这个期间,队列中的任务也执行了一些,相当与给线程池 一些缓冲的时间

手动创建线程池 -- 结合业务确定线程池

image.png

线程数的确定

image.png

JDK提供的线程池

newFixedThreadPool

image.png

newSingleThreadPool

image.png

newCachedThreadPool

image.png

newScheduleThreadPool

image.png

停止线程池

image.png

钩子方法

每个任务执行前后,日志,统计 自定义线程池,添加暂停和恢复功能

image.png

线程池状态

image.png

ThreadLocal

image.png

image.png

image.png

image.png

image.png

image.png

image.png