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的实现类:

未完待续。。

相关推荐
寻星探路4 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
lly2024065 小时前
Bootstrap 警告框
开发语言
2601_949146536 小时前
C语言语音通知接口接入教程:如何使用C语言直接调用语音预警API
c语言·开发语言
曹牧6 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
KYGALYX6 小时前
服务异步通信
开发语言·后端·微服务·ruby
zmzb01036 小时前
C++课后习题训练记录Day98
开发语言·c++
爬山算法7 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty7257 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎7 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven