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

未完待续。。

相关推荐
lubiii_1 分钟前
MCP应用:cursor+hexstrike-ai的安全实战
开发语言·web安全·ai·php
stillaliveQEJ2 分钟前
【JavaEE】Spring AOP(二)
java·spring·java-ee
是罐装可乐5 分钟前
前端架构知识体系:深入理解 sessionStorage、opener 与浏览器会话模型
开发语言·前端·javascript·promise·语法糖
cd ~/Homestead6 分钟前
PHP 变量、类型、运算符
android·开发语言·php
何中应9 分钟前
在Coze上新建一个插件
开发语言·python·ai
岁岁种桃花儿10 分钟前
Spring Boot项目核心配置:parent父项目详解(附实操指南)
java·spring boot·spring
YYHPLA13 分钟前
【无标题】
java·spring boot·后端·缓存
木易 士心14 分钟前
加密与编码算法全解:从原理到精通(Java & JS 实战版)
java·javascript·算法
专注于大数据技术栈15 分钟前
java学习--ArrayList
java·学习
郝学胜-神的一滴17 分钟前
深入理解Qt中的坐标系统:鼠标、窗口与控件位置详解
开发语言·c++·qt·程序人生