线程的状态
线程状态
一、线程的五大状态
二、线程方法
停止线程
不推荐使用 JDK 提供的 stop、destroy 方法。这两个方法已经废弃。
推荐线程自己停止下来。建议使用一个标识位 flag 进行终止线程。当 flag = false时,程序运行结束,线程自动结束,就终止线程运行。
package com.gcbeen.thread;
public class TestStop implements Runnable {
// 1. 线程运行当标识
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag) {
System.out.println("run ... Thread " + i++);
}
}
// 2.设置一个公开的方法停止线程,转换标识位
public void stop() {
this.flag = false;
}
public static void main(String[] args) {
TestStop stop = new TestStop();
new Thread(stop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main..." + i);
if (i == 900) {
// 调用stop()切换标识位,让线程终止
stop.stop();
System.out.println("线程该停止了");
}
}
}
}
线程休眠
sleep 方法指定当前线程阻塞的毫秒数,时间达到后线程进入就绪状态,可以模拟网络延迟和倒计时。sleep 方法 存在 InterruptException 异常。每个对象都有一个锁,调用 sleep 方法,当前线程阻塞时不会释放锁。
模拟网络延迟:放大问题的发生性
package com.gcbeen.thread;
// 模拟网络延迟:放大问题的发生性
public class TestSleepThread01 implements Runnable {
// 票数
private int ticketNums = 10;
public static void main(String[] args) {
TestSleepThread01 thread01 = new TestSleepThread01();
new Thread(thread01, "张三").start();
new Thread(thread01, "李四").start();
new Thread(thread01, "王五").start();
new Thread(thread01, "赵六").start();
}
@Override
public void run() {
while (true) {
if (ticketNums <= 0) {
break;
}
// 捕获异常
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "---》拿到了第" + ticketNums + "张票");
ticketNums--;
}
}
}
模拟倒计时
package com.gcbeen.thread;
public class TestSleepThread02 {
public static void main(String[] args) {
try {
tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 模拟倒计时
public static void tenDown() throws InterruptedException {
int num = 10;
while (true) {
Thread.sleep(1000);
System.out.println(num--);
if (num <= 0) {
break;
}
}
}
}
获取当前系统时间
package com.gcbeen.thread;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestSleepThread03 {
public static void main(String[] args) {
// 获取当前系统时间
Date date = new Date(System.currentTimeMillis());
while (true) {
try {
Thread.sleep(1000);
// 更新系统时间
System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
date = new Date(System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程礼让
让当前正在执行的线程暂停但不阻塞当前线程。将线程从运行状态转换为就绪状态,让 cpu 重新调度。礼让不一定成功。
package com.gcbeen.thread;
public class TestThread {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程开始执行");
Thread.yield(); // 礼让
System.out.println(Thread.currentThread().getName() + "线程停止执行");
}
}
// a线程开始执行
// b线程开始执行
// a线程停止执行
// b线程停止执行
线程插队
join 合并线程,等待此线程执行完成后,再执行其他线程。其他线程阻塞。
package com.gcbeen.thread;
public class TestJoinThread implements Runnable {
public static void main(String[] args) throws InterruptedException{
// 启动线程
TestJoinThread joinThread = new TestJoinThread();
Thread thread = new Thread(joinThread);
thread.start();
// 主线程
for (int i = 0; i < 500; i++) {
if(i==200){
// 插队,main 线程阻塞
thread.join();
}
System.out.println("main" + i);
}
}
@Override
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println("线程VIP" + i);
}
}
}
三、线程状态观测
线程可以处于以下状态之一:
NEW
尚未启动 start 的线程RUNNABLE
在java 虚拟机中执行的线程BLOCKED
被阻塞等待监视器锁定的线程WAITING
等待另一个线程执行特定动作 的线程TIMED_WAITING
等待另一个线程执行一个动作达到了等待时间 的线程TERMINATED
已经退出的线程
一个线程在一个时间点只会处于一个状态,这些状态是虚拟机里面的状态,不反映操作系统里面的状态。
getState 方法
package com.gcbeen.thread;
// 观察测试线程状态
public class TestThreadState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("------结束--------");
});
// 观察状态
Thread.State state = thread.getState();
System.out.println(state);
// 观察启动后
thread.start();
state = thread.getState();
System.out.println(state); // Run
while (state != Thread.State.TERMINATED) {
// 只要线程不终止,就一直输出状态
Thread.sleep(100);
state = thread.getState(); // 更新线程状态
System.out.println(state);
}
// 死亡后的线程不能再启动了,启动会报异常
// thread.start();
}
}
// NEW
// TIMED_WAITING
// TIMED_WAITING
// ...
// TIMED_WAITING
// TIMED_WAITING
// ------结束--------
// TERMINATED
四、线程优先级
Java 提供一个线程调度器来监控程序启动后进入就绪状态的所有线程。线程调度器按照优先级决定调度哪个线程来执行。优先级高只是获取调度的概率高,优先级低获取调度的概率就低。真正的调度由 CPU 决定。
线程的优先级用数字表示,范围从1~10。
// 最小优先级
public final static int MIN_PRIORITY = 1;
// 默认优先级
public final static int NORM_PRIORITY = 5;
// 最大优先级
public final static int MAX_PRIORITY = 10;
使用以下方式改变或者获取优先级
thread.getPriority();
thread.setPriority(5);
建议:优先级的设定在 start 方法调用前。
package com.gcbeen.thread;
public class TestThreadPriority {
public static void main(String[] args) {
// 主线程默认优先级
System.out.println(Thread.currentThread().getName()
+ "-->" + Thread.currentThread().getPriority());
MyPriority myPriority = new MyPriority();
Thread thread1 = new Thread(myPriority);
Thread thread2 = new Thread(myPriority);
Thread thread3 = new Thread(myPriority);
Thread thread4 = new Thread(myPriority);
Thread thread5 = new Thread(myPriority);
// 先设置优先级,再启动
thread1.start();
thread2.setPriority(1);
thread2.start();
thread3.setPriority(4);
thread3.start();
// MAX_PRIORITY=10
thread4.setPriority(Thread.MAX_PRIORITY);
thread4.start();
thread5.setPriority(8);
thread5.start();
}
}
class MyPriority implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+ "-->" + Thread.currentThread().getPriority());
}
}
// main-->5
// Thread-0-->5
// Thread-1-->1
// Thread-2-->4
// Thread-3-->10
// Thread-4-->8
五、守护线程
线程分为用户线程和守护线程。虚拟机必须确保用户线程执行完毕,虚拟机不用等待守护线程执行完毕。守护进程如:后台记录操作日志,监控内存垃圾回收等。
package com.gcbeen.thread;
// 测试守护线程
public class TestDemoThread {
public static void main(String[] args) {
God god = new God();
You you = new You();
Thread thread = new Thread(god);
// 默认false表示是用户线程,正常线程都是用户线程
thread.setDaemon(true);
// 耶稣守护线程启动
thread.start();
// 你 用户线程启动
new Thread(you).start();
}
}
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("耶稣都救不了你!");
}
}
}
class You implements Runnable{
@Override
public void run() {
System.out.println("------你好,世界!------");
for (int i = 0; i < 36500; i++) {
System.out.println("每天都很开心!");
}
System.out.println("------再见,世界!------");
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现