Java多线程状态控制与阻塞详解
本文承接前篇内容,聚焦于Java多线程的阻塞状态与线程控制。详细解析了join()、sleep()、后台线程(Daemon)、线程优先级(setPriority)及线程让步(yield())等核心API的原理、操作步骤及代码示例,旨在帮助开发者在并发编程中更精细地掌控线程执行流程。
四、Java多线程的阻塞状态与线程控制
在理解了线程的基本生命周期后,掌握如何精确控制线程的执行顺序和状态至关重要。以下将逐一解析引起Java线程进入特定状态或行为的主要方法。
第1步:使用 join() 等待线程完成
目的:让调用该方法的线程(通常为父线程)等待目标线程执行完毕后再继续执行,常用于解决线程间的依赖关系。
- 原理:若在线程A的执行体中调用线程B的
join()方法,线程A将被阻塞,直到线程B执行完退出,线程A才会恢复执行。 - 操作示例:主线程在特定条件下启动子线程并立即调用其
join(),确保子线程处理完成后主线程再继续循环输出。
public class ThreadTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 30) {
thread.start();
try {
// main线程需等待thread线程执行完后才能继续
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
第2步:使用 sleep() 暂停线程执行
目的:使当前正在执行的线程暂停指定时间,直接进入阻塞状态,不会释放锁但会放弃CPU时间片。
- 特性:睡眠期间,即使系统无其他可执行线程,该线程也不会执行。常用于模拟耗时操作或调节节奏。
- 调度技巧:新建线程调用
start()后处于就绪状态,若希望其在极短时间内必然获得执行机会,可调用当前线程(通常是主线程)的Thread.sleep(1),利用微小延迟让出CPU给新线程。
public class ThreadTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 30) {
thread.start();
try {
// 使得thread必然能够马上得以执行
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
注意:睡眠时间设置为毫秒级通常足够,因为CPU调度器会在短暂空闲后切换到就绪队列中的其他线程。
第3步:配置后台线程 Daemon Thread
目的:为前台线程提供服务的“守护线程”,典型代表如JVM的垃圾回收线程。
- 生命周期规则:当所有前台线程结束时,后台线程会自动终止,无需等待其执行完毕。后台线程中创建的线程默认仍为后台线程。
- 设置操作:
- 必须在
start()调用之前调用setDaemon(true),否则抛出IllegalThreadStateException。 - 判断是否后台线程使用
isDaemon()。 - 继承关系:Main线程默认为前台;前台线程创建的字线程默认为前台;后台线程创建的字线程默认为后台。
- 必须在
public class ThreadTest {
public static void main(String[] args) {
Thread myThread = new MyThread();
for (int i = 0; i < 100; i++) {
System.out.println("main thread i = " + i);
if (i == 20) {
// 必须在线程启动前设置为后台线程
myThread.setDaemon(true);
myThread.start();
}
}
}
}
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("i = " + i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
第4步:调整线程优先级 setPriority()
目的:影响线程获取CPU时间的概率,而非强制优先执行。
- 取值范围:1-10。常用静态常量:
MAX_PRIORITY(10)NORM_PRIORITY(5)MIN_PRIORITY(1)
- 默认值:新线程默认继承创建它的线程的优先级。Main线程默认具有普通优先级(NORM_PRIORITY)。
- 操作方法:使用
setPriority(int priorityLevel)设置,使用getPriority()获取。
public class ThreadTest {
public static void main(String[] args) {
Thread myThread = new MyThread();
for (int i = 0; i < 100; i++) {
System.out.println("main thread i = " + i);
if (i == 20) {
// 设置最高优先级
myThread.setPriority(Thread.MAX_PRIORITY);
myThread.start();
}
}
}
}
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("i = " + i);
}
}
}
注:高优先级仅代表拥有较多执行机会,在竞争激烈时仍需遵循OS调度算法,不能保证绝对优先。
第5步:线程让步 yield()
目的:让当前处于运行状态的线程主动退回到就绪状态,将CPU让给其他同级或更高级别的线程。
- 工作机制:调用
yield()后,CPU会从就绪队列中选择与该线程优先级相同或更高的线程去执行。如果就绪队列中没有同等或更高优先级的线程,则该线程可能立即再次获得执行权。 - 操作示例:对比高低优先级线程的表现,并在主线程适当时机调用
yield()。
public class ThreadTest {
public static void main(String[] args) {
Thread myThread1 = new MyThread1();
Thread myThread2 = new MyThread2();
myThread1.setPriority(Thread.MAX_PRIORITY);
myThread2.setPriority(Thread.MIN_PRIORITY);
for (int i = 0; i < 100; i++) {
System.out.println("main thread i = " + i);
if (i == 20) {
myThread1.start();
myThread2.start();
// 主线程让步,观察其他线程执行情况
Thread.yield();
}
}
}
}
class MyThread1 extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("myThread 1 -- i = " + i);
}
}
}
class MyThread2 extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("myThread 2 -- i = " + i);
}
}
}
总结
通过合理运用 join()、sleep()、后台线程设置、优先级调整及 yield(),开发者可以更精细地控制Java多线程程序的执行流程和资源竞争状况。理解这些方法的具体行为和适用场景,是编写高效、稳定并发应用的基础。
以上就是Java多线程状态控制与阻塞机制的详细内容,更多关于Java并发编程的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









