线程基本使用

创建线程的两种方式

  1. 继承Thread类,重写run方法 启动线程直接调用start
  2. 实现Runnable接口,重写run方法 启动线程时,先Thread thread = new Thread(*),把对象传进去,再用thread.start()来启动线程

重写run方法,写上自己的业务代码 Thread类中的run实现了Runnable接口的run方法

当main线程启动一个子线程,主线程不会阻塞,会继续执行

callable方式创建线程

前两种方式,加入线程执行完毕后有数据需要返回,重写的run方法无法直接返回结果-----Callable接口和FutureTask类可以返回执行完毕后的结果

流程

  1. 创建任务对象
    1. 定义一个类实现Callable接口,重写call方法,封装要做的事,和要返回的数据
    2. 把Callable类型的对象封装成FutureTask对象(线程任务对象)---FutureTask对象实现了Runnable接口
  2. 后面同上两种方式,把FutureTask对象交给Thread对象
  3. 调用Thread对象的start方法启动线程
  4. 线程执行完毕后、通过FutureTask对象的get方法去获取线程任务执行的结果。此处的get方法会等待线程执行完毕再get,保证能拿到结果

优缺点

  1. 优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后获取线程执行的接口
  2. 缺点:编码复杂

为什么用start,而不是直接调用run方法

  1. 直接调用run方法,是用的原线程调用的,就是一个普通的方法,没有真正启动一个线程,就是把run方法执行完毕,才向下执行。
  2. 使用start才是开启一个新的线程。

继承Thread vs 实现Runnable的区别

  1. 从java设计来看,继承Thread或者实现Runnable接口来创建线程本质上没有区别,从jdk帮助文档我们可以看到Thread类本身就实现了Runnable接口
  2. 实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制.

线程终止

  1. 线程完成任务后,会自动退出
  2. 还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式

线程常用方法-1

  1. setName //设置线程名称
  2. getName
  3. start //使线程开始执行;java虚拟机底层调用该线程的start0方法
  4. run
  5. setPriority
  6. getPriority
  7. sleep
  8. interrupt// 中断线程

注意-1

  1. start底层会创建新的线程,调用run,run就是一个简单方法的调用,不会启动新线程
  2. 线程优先级范围
  3. interrupt, 中断线程,并没有真正结束线程,所以一般用于中断正在休眠的线程
  4. sleep: 线程的静态方法,使当前线程休眠

线程常用方法-2

  1. yield:线程的礼让。让出cpu,让给其他线程执行,但礼让的时间不确定,所以也不一定礼让成功
  2. join:线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程的所有任务。

用户线程和守护线程

  1. 用户线程:也叫工作线程,当线程的任务执行完或通知方式结束
  2. 守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束
  3. 常见的守护线程:垃圾回收机制

线程的生命周期

alt text 七个状态,官网文档把Ready和Running看做一个Runnable状态
所以Runnable状态不一定就在执行,Ready到Running由线程调度器调度


本文章使用limfx的vscode插件快速发布