Java多线程状态控制与阻塞详解

落日邮差
落日邮差
发布时间:2026-10-13 | 2人浏览过
原创

本文承接前篇内容,聚焦于Java多线程的阻塞状态与线程控制。详细解析了join()、sleep()、后台线程(Daemon)、线程优先级(setPriority)及线程让步(yield())等核心API的原理、操作步骤及代码示例,旨在帮助开发者在并发编程中更精细地掌控线程执行流程。

四、Java多线程的阻塞状态与线程控制

在理解了线程的基本生命周期后,掌握如何精确控制线程的执行顺序和状态至关重要。以下将逐一解析引起Java线程进入特定状态或行为的主要方法。

第1步:使用 join() 等待线程完成

目的:让调用该方法的线程(通常为父线程)等待目标线程执行完毕后再继续执行,常用于解决线程间的依赖关系。

  1. 原理:若在线程A的执行体中调用线程B的 join() 方法,线程A将被阻塞,直到线程B执行完退出,线程A才会恢复执行。
  2. 操作示例:主线程在特定条件下启动子线程并立即调用其 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时间片。

  1. 特性:睡眠期间,即使系统无其他可执行线程,该线程也不会执行。常用于模拟耗时操作或调节节奏。
  2. 调度技巧:新建线程调用 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的垃圾回收线程。

  1. 生命周期规则:当所有前台线程结束时,后台线程会自动终止,无需等待其执行完毕。后台线程中创建的线程默认仍为后台线程。
  2. 设置操作:
    • 必须在 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. 取值范围:1-10。常用静态常量:
    • MAX_PRIORITY (10)
    • NORM_PRIORITY (5)
    • MIN_PRIORITY (1)
  2. 默认值:新线程默认继承创建它的线程的优先级。Main线程默认具有普通优先级(NORM_PRIORITY)。
  3. 操作方法:使用 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让给其他同级或更高级别的线程。

  1. 工作机制:调用 yield() 后,CPU会从就绪队列中选择与该线程优先级相同或更高的线程去执行。如果就绪队列中没有同等或更高优先级的线程,则该线程可能立即再次获得执行权。
  2. 操作示例:对比高低优先级线程的表现,并在主线程适当时机调用 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并发编程的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表