前提:
虚拟线程:
在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的实现类:
未完待续。。