Java并发编程-Java线程

文章目录

目录

文章目录

前言

一、线程创建与启动

二、线程运行原理

三、常见的作用于线程的方法

四、线程运行时状态

总结


前言

主要介绍了Java并发编程中的Java线程。


一、线程创建与启动

  • 创建完线程后需要用start函数启动线程,使其处于就绪态(thread.start())(是否可以竞争到CPU处于运行态取决于任务调度器),每个线程只能start一次,多线程一起运行时由任务调度器自行分配时间片交替运行
  • 子类
    • 匿名内部类写法,继承Thread的子类,在子类中覆盖重写run方法
    • Thread thread=new Thread(){public void run()->{//待执行任务} }
      (可替换为lambda简化写法)
      Thread thread=()->{//待执行代码块}
    • 线程与任务融合为一体
  • Runnable
    • 在Runnable对象中定义待执行任务的run方法,传入Thread对象作为其成员变量,调用Thread中的run方法时,会先检查成员变量Runnable对象是否存在,存在则执行Runnable的run方法
    • Runnable r=new Runnable(){public void run(){//待执行代码块}};Thread thread=new Thread(r,name:"t")
      (可替换为lambda简化写法)
      Thread thread=new Thread(()->{//待执行代码块},name:“t”)
    • 线程与任务分开
  • FutureTask
    • 间接实现Runnable和Future(内有get方法可以获取返回值)接口,可以传入callable对象并在其中写call方法(相当于有返回值的run方法)传入Thread线程中
    • FutureTask<返回值类型> task=new FutureTask(new Callable<>() { public 返回值类型 call() {//待执行方法} } ); Thread thread=new Thread(task,“t”)
    • 线程与任务分开

二、线程运行原理

  • 栈与栈帧
    • JVM给每个线程分配一个栈空间,线程中调用的方法会在其栈中对应一个栈帧,栈帧有指向方法区中运行中常量池符号引用的引用,常量池中的符号引用解析后指向方法区中加载阶段由JVM写入方法区的方法的指令字节流
    • 虚拟机栈是线程私有的,每个线程对应一个自己的栈空间,线程中被调用的方法对应该线程栈中的栈帧
  • 线程上下文切换
    • 定义
      • 当线程a不再继续占用CPU时,需要保存线程a的执行状态,并将下一个执行的线程b状态写入CPU执行
    • 切换的时机
      • 时间片到、垃圾回收,高级线程到达,线程自己放弃CPU去sleep、join、yield、、、

三、常见的作用于线程的方法

  • start和run
    • start是启动线程的方法,run是线程用start启动后自动执行的方法
    • 不用start启动线程而是直接调用run方法无法起到利用多线程提高运行效率的效果,run方法将在调用线程中执行而不是其定义的线程中
    • 只有在线程创建完成后主动调用start方法启动该线程,才能在该线程中执行run方法
  • sleep和yield
    • sleep是线程的static静态方法,线程调用sleep方法后会放弃CPU陷入阻塞(TIMED WAITING或WAITING)不被任务调度器考虑,等睡眠时间结束或被interrupt方法唤醒后才被任务调度器看到处于可运行状态与其他线程一起争夺CPU
      单核处理器中线程有while(true)语句时,在其中写sleep方法放弃一下CPU可以防止一个线程100%占用CPU
    • 线程调用yield方法会暂时放弃CPU,但是任务调度器还会让该线程参与下一次CPU的竞争,该线程会立即变成可运行状态在任务调度器中与其他线程争抢CPU,若此时没有其他线程则会继续执行被yield了的线程
  • setpriority线程优先级
    • 让任务调度器优先考虑优先级别高的线程,但是实际的运行还是无法由程序员控制,都是由任务调度器实现
    • (与yield类似)只是通知任务调度器最好将某个线程暂停或减少使用(yield)或者多考虑某些优先级高的线程少考虑某些优先级低的线程(setpriority)
  • join
    • 需要实现多线程同步时可以在想等待线程a的线程b中调用线程a的join方法,让b等待a执行完成后在继续执行
    • 在线程b中调用线程a的join方法后,线程b将处于阻塞状态(WAITING或者TIMED WAITING),等到等待时间结束或a线程调用结束后或被interrupt了,b线程将重新处于可运行状态在任务调度器中与其他线程抢占CPU
  • interrupt
    • 打断sleep、join、wait(抢到锁但缺少某个条件时陷入Waiting状态阻塞等待条件满足)的阻塞线程
      • interrupt将打断标志记为真,阻塞线程被异常捕获,后会清空打断标志使其又变为假,下次还可以进入阻塞状态
    • 打断正常运行线程
      • interrupt将打断状态置为真,正常运行线程获取打断标记,后自行决定是否结束运行,打断标记不会被清空还是为真
    • 打断park线程
      • interrupt将打断标记置为真,park住的线程获取打断标记被打断,后打断标记不会被清空还是为真,无法再被park阻塞住(park了立即被打断因为打断标记是真)
    • 获取打断标记
      • isInterrupted
        • 获取打断标记后,不清空标记
      • interrupted
        • 获取打断标记后,清空标记
  • 守护线程
    • 普通线程会等待所有线程运行结束后一起退出,守护线程在非守护线程运行结束后立即退出(无需考虑自身运行情况直接退出)

四、线程运行时状态

  • 操作系统五状态
    • 开始
    • 可运行(就绪)
    • 运行
    • 阻塞(执行一些耗时较长的读写IO操作时放弃占用CPU)
    • 结束
  • java六状态
    • NEW
      • 仅创建线程未调用start方法
    • RUNNABLE
      • 可运行、运行、阻塞(执行读写IO操作时放弃cpu了但是java仍然认作runnable状态)
    • TERMINATED
    • BLOCKED
      • 等待锁时陷入的阻塞
    • TIMED WAITING
      • 有时间限制的等待如线程调用sleep(n)、join(n)
      • 或者获得锁对象后缺少条件,锁对象调用wait(n),等待必要条件时
      • 线程中使用LockSupport调用parknanos(n)、parkutil(n)陷入阻塞,等待“干粮”counter被补充
    • WAITING
      • 没有时间限制的等待如线程调用sleep、join
      • 或者获得锁对象后缺少条件,锁对象调用wait,等待必要条件时
      • 线程中使用LockSupport调用park()陷入阻塞,等待“干粮”counter被补充

总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值