线程的状态

线程状态

一、线程的五大状态

在这里插入图片描述在这里插入图片描述

二、线程方法

在这里插入图片描述

停止线程

不推荐使用 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("------再见,世界!------");
    }
}
posted @   gcbeen  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示