开启线程后主线程会阻塞嘛?
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线程。
-
分配线程组
scssif (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()方法