1. 线程的状态操作概述
默认情况下,一个处于就绪状态的线程何时执行,由操作系统的调度器来决定。但是在很多实际的应用场景中,经常需要开发者人为的对线程的状态进行控制。例如,控制某个线程在其他线程执行完成后再执行,或者控制某个线程休眠一段时间等。
Java提供了多个可以操作线程状态的方法。例如:
- sleep():控制某个线程休眠一段时间
- join():控制某个线程等待另一个线程执行完成后再执行
- yield():控制一个线程从运行状态切换到就绪状态
- interrupt():向线程发送一个中断通知
2. sleep 方法
Thread 的静态方法 sleep 用于使当前线程进入阻塞状态,语法为:
static void sleep(long ms)
该方法会使当前线程进入阻塞状态指定毫秒,当阻塞指定毫秒后,当前线程会重新进入 Runnable 状态,等待分配时间片.
该方法声明会抛出一个InterruptException,因此在使用该方法时需要捕获这个异常。
编写代码,测试sleep方法,实现要求如下:

代码示意如下:
import java.time.LocalTime;
import java.util.concurrent.TimeUnit;
public class SleepDemo {
public static void main(String[] args) {
Thread t1 = new Thread( () -> {
try{
System.out.println("正在运行的线程名称:"
+Thread.currentThread().getName()
+" 开始时间 = " + LocalTime.now());
// 延时2秒
// Thread.sleep(2000);
TimeUnit.SECONDS.sleep(2); // 1.5新语法 可读性更好
System.out.println("正在运行的线程名称:"+
Thread.currentThread().getName()+
" 结束时间 = " + LocalTime.now());
}catch(InterruptedException e){
e.printStackTrace();
}
} );
System.out.println("主线程开始时间 = " + LocalTime.now());
t1.start();
System.out.println("主线程结束时间 = " + LocalTime.now());
}
}
3. join 方法
Thread 的 方法 join 用于等待当前线程结束,语法如下:
void join()
该方法声明抛出InterruptException。

import java.util.concurrent.TimeUnit;
public class JoinDemo {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRun2(), "t1");
Thread t2 = new Thread(new MyRun2(), "t2");
Thread t3 = new Thread(new MyRun2(), "t3");
t1.start();
// 主线程等待t1线程死亡或等待2秒后向下执行启动t2线程
try {
// t1.join(2000);
TimeUnit.SECONDS.timedJoin(t1, 2); // 1.5新语法
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
// 主线程等待t1线程死亡后再向下执行启动t3线程的代码
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t3.start();
// 主线程等待t1线程、t2线程和t3线程死亡后再向下执行
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("All threads are dead, exiting main thread");
}
}
// 多个线程复用的场景,使用Runnable接口实现类
class MyRun2 implements Runnable{
@Override
public void run() {
System.out.println("Threadstarted:::"
+Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread ended:::"
+Thread.currentThread().getName());
}
}
4. yield 方法
Thread 的静态方法 yield 语法如下:
static void yield()
该方法用于使当前线程主动让出当次CPU时间片回到Runnable状态,等待分配时间片。比如对正在运行中的线程1调用 yield 方法,则进入就绪状态:

编写代码,测试yield方法,代码示意如下:
public class YieldDemo {
public static void main(String[] args){
Runnable run = () -> {
String name = Thread.currentThread().getName();
for (int i = 0;i<8;i++){
System.out.println(name+":"+i);
if(i == 5){
// 主动释放CUP使用权
Thread.yield();
}
}
};
Thread t1 = new Thread(run,"Thread1");
t1.start();
Thread t2 = new Thread(run,"Thread2");
t2.start();
}
}
5. interrupt方法
Thread 的静态方法 interrupt 用于设置线程的中断状态。该方法试图将目标线程的中断标志设置为true,最终结果取决于线程的当前状态。
对于当前处于运行状态的线程,调用interrupt方法后,线程的中断标识设置为true。如下图所示:

interrupt中断休眠示例,编写代码,测试使用interrupt方法中断休眠。代码示意如下:
import java.util.concurrent.TimeUnit;
public class InterruptDemo1 {
public static void main(String args[]) {
Thread thread = new Thread(() -> {
System.out.println("线程启动了");
try {
TimeUnit.MINUTES.sleep(3);
} catch (InterruptedException e) {
System.out.println("抛出异常对象: "+e);
}
System.out.println("线程结束了");
});
thread.start(); // 启动子线程
try {
// 主线程休眠5秒
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 在线程阻塞时抛出一个中断信号
// 这样线程就得以退出阻塞状态
thread.interrupt();
}
}
通过interrupted标识终止线程示例,可以通过循环确认某个线程的interrupted标识来控制一个线程的运行状态。
import java.util.concurrent.TimeUnit;
public class InterruptDemo2 {
public static void main(String args[]) {
Thread thread = new Thread(() -> {
Thread cThread = Thread.currentThread();
System.out.println("线程启动了");
// while循环持续检测线程的中断标识
while (!cThread.isInterrupted()){
System.out.println("Thread say...");
}
System.out.println("线程结束了");
});
thread.start(); // 启动子线程
try {
// 主线程休眠1毫秒
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 向运行中的子线程发送一个中断通知
thread.interrupt();
}
}
6. 其他阻塞状态
线程的阻塞状态可细分为:等待阻塞、同步阻塞和其他阻塞。前两者和线程的同步相关,将在后续的课程中介绍。其他阻塞是指因调用线程的sleep方法或join方法而导致的线程阻塞,如下图所示:

输入/输出请求是指与其他程序或者与操作系统的输入/输出接口进行交互的场景,由于被访问的数据可能需要一定的准备工作,输入/输出操作是线程阻塞的常见原因。

本文详细介绍了Java中线程状态的控制方法,包括sleep用于线程休眠、join用于等待线程结束、yield让出CPU时间片、interrupt中断线程,以及不同阻塞状态的含义。
950

被折叠的 条评论
为什么被折叠?



