目录
线程的生命周期
一、新建状态(New)
二、就绪状态(Runnable)
三、运行状态(Running)
四、阻塞状态(Blocked)
五、死亡状态(Dead)
什么是双亲委派
continue、break和return的区别是什么?
线程的生命周期
一、新建状态(New)
- 当程序使用
new
关键字或其他线程创建方法(如Win32的API或.NET框架的API)创建了一个线程对象后,该线程就处于新建状态。此时,线程对象已经分配了必要的内存空间并初始化了成员变量,但它还没有开始执行,即没有表现出任何动态特征。 - 在这个阶段,线程的执行体(通常是
run
方法)还没有被启动,线程对象仅仅是一个普通的Java对象(或其他编程语言的相应对象)。
二、就绪状态(Runnable)
- 当调用线程的
start
方法后,线程就进入了就绪状态。此时,线程已经做好了执行准备,表示可以运行了,但还不是正在运行的线程。 - 就绪状态的线程已经分配了线程ID和线程上下文(包括特定于CPU的寄存器信息等),并且已经创建和初始化了用户态栈和内核态栈。
- 在这个阶段,线程还没有获得CPU的调度权,因此不会立即执行。线程需要等待JVM(Java虚拟机)中的线程调度器将其调度到运行状态。
三、运行状态(Running)
- 当就绪状态的线程获得JVM中线程调度器的调度时,线程就进入了运行状态。此时,线程开始执行其执行体(
run
方法)中的代码。 - 线程在运行过程中可能会因为时间片用完、主动让出CPU资源(如调用
yield
方法)或其他原因(如等待I/O操作完成、等待同步锁等)而进入阻塞状态或就绪状态。 - 在多CPU的机器上,可能会有多个线程同时处于运行状态;但在单CPU的机器上,任何时刻只有一条线程处于运行状态。
四、阻塞状态(Blocked)
- 线程在运行过程中可能会因为各种原因而进入阻塞状态。阻塞状态是线程暂时停止执行并等待某个条件满足的状态。
- 线程阻塞的原因可能包括:调用
sleep
方法主动放弃CPU资源、等待I/O操作完成、等待同步锁(如试图获取一个已被其他线程持有的同步监视器)等。 - 被阻塞的线程会在合适的时候(如阻塞条件解除后)重新进入就绪状态,并等待线程调度器再次调度它执行。
五、死亡状态(Dead)
- 当线程的
run
方法执行完成或线程抛出未捕获的异常时,线程就会进入死亡状态。此时,线程已经完成了其生命周期并终止执行。 - 线程死亡后,其占用的资源(如用户态栈、内核态栈等)将被释放。同时,线程的引用计数将减1,当引用计数变为0时,线程内核对象将被销毁。
综上所述,线程的生命周期包括新建状态、就绪状态、运行状态、阻塞状态和死亡状态。这些状态之间的转换通常是由线程的调度、执行和阻塞等操作引起的。了解线程的生命周期有助于更好地理解线程的并发执行机制和资源管理策略。
什么是双亲委派
双亲委派模式是指Java虚拟机在加载类时采用的一种加载策略。具体来说,当一个类加载器收到类加载的请求时,它并不会自己先去加载该类,而是将这个请求委托给父类的加载器去执行。这个过程会一直递归进行,直到达到顶层的引导类加载器(Bootstrap ClassLoader)。如果父类加载器能够完成类加载任务,就成功返回;如果父类加载器无法完成类加载任务,子加载器才会尝试自己去加载。
双亲委派模式的主要目的是:
- 避免重复加载:通过双亲委派模式,可以确保同一个类只被加载一次,从而避免重复加载导致的资源浪费和潜在的问题。
- 保护核心类库:双亲委派模式还可以防止恶意代码通过自定义类加载器来篡改Java的核心类库。
例如,在加载jdbc.jar用于实现数据库连接的时候,因为jdbc.jar是基于Java中rt.jar中的SPI接口进行实现的,所以在加载的时候,由于SPI接口会调用实现类中的方法,所以这里jdbc.jar中的方法会被加载到内存中,此时就会进行双亲委派进行类加载。最终从Bootstrap ClassLoader类加载器中加载SPI核心类,然后加载SPI接口的实现类,此时Bootstrap ClassLoader会进行反向委派,通过线程上下文类加载器进行jdbc.jar的加载,从而避免类的重复加载并保护程序安全。
因此,“双清委派”并非一个标准的计算机科学或Java领域的术语,而“双亲委派模式”才是Java虚拟机在类加载过程中采用的一种重要机制。
continue、break和return的区别是什么?
在循环结构中,当循环条件不满足或者循环次数达到要求时,循环会正常结束。但是,有时候可能需要在循环的过程中,当发生了某种条件之后 ,提前终止循环,这就需要用到下面几个关键词:
continue
:指跳出当前的这一次循环,继续下一次循环。break
:指跳出整个循环体,继续执行循环下面的语句。
return
用于跳出所在方法,结束该方法的运行。return 一般有两种用法:
return;
:直接使用 return 结束方法执行,用于没有返回值函数的方法return value;
:return 一个特定值,用于有返回值函数的方法
public static void main(String[] args) {boolean flag = false;for (int i = 0; i <= 3; i++) {if (i == 0) {System.out.println("0");} else if (i == 1) {System.out.println("1");continue;} else if (i == 2) {System.out.println("2");flag = true;} else if (i == 3) {System.out.println("3");break;} else if (i == 4) {System.out.println("4");}System.out.println("xixi");}if (flag) {System.out.println("haha");return;}System.out.println("heihei");
}
运行的结果是:
0
xixi
1
2
xixi
3
haha