Thread简单的源码阅读

开启线程后主线程会阻塞嘛?

csharp 复制代码
public class Thread01 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.start();
​
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(1000);
                System.out.println("当前线程继续执行" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
​
    }
}
​
class Cat extends Thread {
    @Override
    public void run() {
        int count = 0;
        while (true) {
​
            try {
                System.out.println("喵喵叫、、、、、、、、" + (++count) + Thread.currentThread().getName());
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (count == 30) {
                break;
            }
        }
​
    }
}

代码运行结果

可以看出主线程里面,如果开启了一个其他线程,主线程并不会阻塞。由于CPU的来回切换,一会执行main线程代码一会执行其他线程的代码。

初始化原理

csharp 复制代码
public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}
​
  • 默认情况下,如果不指定线程的名称,那么自动生成的线程名称就是,Thread-0,Thread-1,以此类推的一大堆的线程。
  • 进入到init()方法之后 如下图所示:

说明: 创建线程的时候,获取到的是currentThread(),是当前创建的那个线程,比如说一般来说就是那个main线程,main线程在创建XXXX线程,所以说此时创建线程的过程中,获取到的currentThread()就是main线程

创建一个线程的时候,默认他的父线程就是创建他的那个线程,比如main线程创建XXXX线程,此时XXXX线程的父线程就是main线程。

  • 分配线程组

    scss 复制代码
    if (g == null) {
        /* Determine if it's an applet or not */
    ​
        /* If there is a security manager, ask the security manager
           what to do. */
        if (security != null) {
            g = security.getThreadGroup();
        }
    ​
        /* If the security doesn't have a strong opinion of the matter
           use the parent thread group. */
        if (g == null) {
            g = parent.getThreadGroup();
        }
    }

上面这段代码的意思,就是说threadGroup是不指定的,他就会自动给你处理一下,给你分配一个线程组,每个线程必须属于一个ThreadGroup的。如果你没有指定线程组,那么你默认的线程组就是父线程的线程组。

如果你的父线程是main线程的话,那么你的线程组就是main线程的线程组(main线程组)。默认情况下,如果你没有指定你是否为daemon的话,那么你的daemon的状态是由父线程决定的,就是说如果你的父线程是daemon线程,那么你也是daemon线程;同理,你的优先级如果没有指定的话,那么就跟父线程的优先级保持一致

在 Java 中,有两种类型的线程:用户线程和守护线程(Daemon 线程)。用户线程是指主线程和其他由主线程创建的线程,它们的工作通常是完成一些具体的任务或者实现某些功能。而守护线程是指在后台运行的线程,它们通常用于提供服务和支持其他线程的运行。

守护线程与用户线程的最大区别是,当 JVM 中只有守护线程时,JVM 将会退出。守护线程不会阻止 JVM 的退出,当 JVM 中只有守护线程时,JVM 将会自动退出,而不考虑这些线程是否执行完毕。

ini 复制代码
tid = nextThreadID();

每个线程其实都有一个线程id,threadId,第一个分配的线程,它的id是1,之后的线程是2,3,4,5,这样子,依次分配各个线程的id

总结:

(1)创建你的线程,就是你的父线程

(2)如果没有指定ThreadGroup,ThreadGroup就是父线程的ThreadGroup

(3)daemon状态默认是父线程的daemon状态

(4)你的优先级默认是父线程的优先级

(5)如果你没有指定线程的名称,那么默认就是Thread-0格式的名称

(6)你的线程id是全局递增的,从1开始

对一个线程进行start的时候的原理

scss 复制代码
if (threadStatus != 0)
throw new IllegalThreadStateException();

说明永远都不能对一个线程多次调用和执行start()方法,这个是不对的。

如果线程一旦执行过一次以后,那么他的threadStatus就一定会变为非0的一个状态,如果threadStatus是非0的状态,说明他之前已经被执行过了,所以这里会有一个判断,如果对一个线程多次执行start()方法,会抛出一个异常,IllegalThreadStateException,非法的线程状态的异常。

csharp 复制代码
group.add(this);

group就是之前给分配的,如果你自己指定了,那么就是你自己创建的那个ThreadGroup,否则的话就是你的父线程的threadGroup,这行代码,其实就是将当前线程加入了他属于的那个线程组。

csharp 复制代码
private native void start0();

会结合底层的一些代码和机制,实际的启动一个线程。一旦是start0()成功的启动之后,他就会去执行我们覆盖掉的那个run()方法,或者是如果你传入进去的是那个Runnalbe对象,他就会执行那个Runnable对象的方法

csharp 复制代码
public void run() {
        if (target != null) {
            target.run();
        }
}
csharp 复制代码
new Thread(new Runnable() {

public void run() {
}

}).start();

如果传递进去了一个Runnable对象,就是在thread类里是target的东西,会判断一下,如果target为null的话,那么此时就会执行target的run方法。反之,如果你是直接自己用Thread类继承了一个子类的话,那么你会重写这个run()方法,start0()启动线程之后,就会来执行你的run()方法

总结:

(1)一旦启动了线程之后,就不能再重新启动了,多次调用start()方法,因为启动之后,threadStatus就是非0的状态了,此时就不能重新调用了

(2)你启动线程之后,这个线程就会加入之前处理好的那个线程组中

(3)启动一个线程实际上走的是native方法,start0(),会实际的启动一个线程

(4)一个线程启动之后就会执行run()方法

相关推荐
白露与泡影23 分钟前
springboot + nacos + k8s 优雅停机
spring boot·后端·kubernetes
菜鸟谢41 分钟前
windows xp 下载 sp0 sp1 sp2 sp3 sp4
后端
AirMan43 分钟前
你真的懂 MySQL 的一致性读和当前读的区别吗?
后端·面试
David爱编程1 小时前
容器性能优化实战指南——防止“吃爆”服务器就靠这些招!
后端·docker·容器
Android洋芋1 小时前
GitHub项目部署的终极指南:从零到一掌握Docker实战
后端
林太白1 小时前
Next.js超简洁完整篇
前端·后端·react.js
前端付豪1 小时前
汇丰登录风控体系拆解:一次 FaceID 被模拟攻击的调查纪实
前端·后端·架构
无名之逆1 小时前
大三自学笔记:探索Hyperlane框架的心路历程
java·开发语言·前端·spring boot·后端·rust·编程
yang_xiao_wu_1 小时前
springboot+mybatis面试题
spring boot·后端·mybatis
Chuck1sn1 小时前
我把 Cursor AI 整合到 Ruoyi 中,从此让 Java 脚手架脱离人工!
java·vue.js·后端