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

未完待续。。

相关推荐
爱吃大芒果2 小时前
Flutter 主题与深色模式:全局样式统一与动态切换
开发语言·javascript·flutter·ecmascript·gitcode
Coder_Boy_2 小时前
DDD从0到企业级:迭代式学习 (共17章)之 四
java·人工智能·驱动开发·学习
2301_768350232 小时前
MySQL为什么选择InnoDB作为存储引擎
java·数据库·mysql
云栖梦泽2 小时前
易语言数据库操作:结构化数据管理的核心
开发语言
派大鑫wink2 小时前
【Java 学习日记】开篇:以日记为舟,渡 Java 进阶之海
java·笔记·程序人生·学习方法
电子硬件笔记2 小时前
Python语言编程导论第七章 数据结构
开发语言·数据结构·python
南棱笑笑生2 小时前
20251217给飞凌OK3588-C开发板适配Rockchip原厂的Buildroot【linux-5.10】后调通ov5645【只能预览】
linux·c语言·开发语言·rockchip
ulias2122 小时前
C++ 的容器适配器——从stack/queue看
开发语言·c++