Thread及其相关类

前提:

虚拟线程:

在java21之后引入了虚拟线程的概念,需要与java平台线程进行区分

线程(Java SE 21 和 JDK 21)官方文档中介绍了平台线程和虚拟线程

平台线程:一对一映射到操作系统线程;会默认生成一个线程名称;分为守护线程和非守护线程;具有线程优先级;是线程组的成员

虚拟线程:用户线程(由 Java 运行时而不是操作系统调度,且通常使用少量平台线程作为承载线程);不会默认生成线程名称;虚拟线程忽略线程优先级、守护状态等这些概念

runnable和callable接口

在java中,runnable和callable接口都是只包含一个函数的简单接口,且都通@FunctionalInterface注解标志(FunctionalInterface注解用来标志一个接口是函数式接口)

runnable的语义是:可运行的任务,不返回结果也不抛出受检异常

callable与runnable类似,都是可运行的任务,但是可以返回结果,也可以抛出受检异常,是对runnable的补充增强

Thread类

java中通过Thread类与操作系统的线程直接挂钩,Thread类也实现了runnable接口

成员变量:

在引入虚拟线程之后,Thread类的成员变量大致可以分为两类:

保留在Thread主体中的变量:线程名称、tid、ThreadLocal等;还有一些由JVM native代码直接读写的字段,例如threadStatus、eetop等

通过静态内部类Holder持有的变量:虚拟变量通常不支持Holder,里面包含所属线程组、要执行的任务、线程优先级、是否为守护线程、栈大小提示

(像线程组、守护状态、优先级虚拟线程都是固定的,而任务和栈大小是由调度器和JVM动态管理的,不需要分配)

在使用java创建或者操作线程的时候创建的Thread对象其实只是对操作系统线程的一种抽象和封装,这个对象往往存放在堆上,从本质上说和我们创建出的别的对象没有任何区别。而真正创建的与内核线程一一对应的操作系统线程实际是JVM在C++层创建的JavaThread对象。

所以这里其实可以分出三个线程的概念:

操作系统线程:真正在操作系统上执行任务,占据cpu资源的线程

JavaThread:是JVM通过一个C++对象来管理操作系统的线程

java堆中的Thread:暴露给程序员来控制监控线程

JavaThread和Thread是互相持有的,而Thread类中的eetop这个字段指向的就是JavaThread的地址,如果eetop的值为0的话,表示未关联JVM内部的线程对象

关于attached的概念:

在Thread的构造函数中可以看到attached这样一个变量,用来标识当前这个线程是不是一个已附着的线程

attached thread指的是已经由jvm创建并运行,现在需要在java层包装成一个thread对象的线程。

因为普通通过java创建线程实际是通过thread.start()的底层原语去新建线程的,也就是说java层面的Thread对象比操作系统的线程更早建立。但是attached thread却相反,是已经有了线程,但是没有java层面的Thread对象,所以要通过这样一个标志,来走不同的初始化路径,其判断方式就是判断父线程是不是自己

复制代码
Thread parent = currentThread();
boolean attached = (parent == this);   // primordial or JNI attached

这样的线程一般有两种,一种是初始线程,也就是执行main方法的哪个线程;一种是JNI附着线程,native代码可以将一个OS线程附着到JVM上

构造方法:

Thread源码中提供了很多公共的构造方法,但是实际都是调用同一个内部构造器实现的

最重要的参数就是Runnable,即线程要实现的任务,其余的参数都有默认值

Thread中除了创建平台线程的内部构造器之外,还有一个创建虚拟线程的内部构造器,这个构造器不能通过new Thread调用,只能通过Thread.ofVirtual()或Thread.startVirtual()调用(这些内部构造器都是不public的)

可以看到创建线程只能接收runnable接口作为任务体的参数,callable是不能直接传递给Thread创建线程的,所以只能是将callable包装成runnable传递给Thread(适配器设计模式),即通过FutureTask来桥接

FutureTask

FutureTask是RunnableFuture的实现类,字如其名,就是Runnable+Future

作为runnable的实现类:内部持有一个callable的实例,在run方法中调用callable实例的call方法。这样就实现了将callable包装成runnable提交给Thread执行

作为Future的实现类:

未完待续。。

相关推荐
mldong4 小时前
一个 App,十三套后端:手机审批端 uni-jeeflow-app 开源了
java·架构
tqs_123455 小时前
MySQL RR隔离级别死锁|Gap间隙锁、临键锁,订单并发范围查询死锁根因方案
java
逆境不可逃5 小时前
Pi Agent 学习笔记:多个工具怎样并行执行
java
浪子明X5 小时前
十六位账本怎样发现传输差错:Internet Checksum 生活类比
开发语言
Flynt6 小时前
Java 27 升级实测:默认值动得比新特性多,有个老参数会让 JVM 直接起不来
java·jvm·后端
Bs_MoneyMagnet6 小时前
基于springboot+vue的个人健康管理系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·vue3·springboot3·计算机毕业设计
星云API技术支持6 小时前
企业微信二次开发:群权限设置、成员管理与群资料维护的接口组合实践
java·前端·企业微信
niucloud-admin7 小时前
JAVA V6 多商户商城 开发文档——job 计划任务开发
java·python·github
海宇AI8 小时前
零信任架构实战:基于海宇柠檬查出险-登记证构建自动化车抵贷核保网关
java·人工智能·架构·自动化
xiangyun618 小时前
【408数据结构 08】队列:循环队列判空判满,408年年考,一次讲清
c语言·开发语言·数据结构·c++·算法