零基础掌握Java多线程(二):Thread核心属性

一、ID

ID是线程的唯一标识,不同线程不会重复

获取方法


使用getId()方法可以获取线程的ID

代码示例:

public class ThreadIdDemo {
    public static void main(String[] args) {
        new Thread(()-> System.out.println("该线程ID:" + Thread.currentThread().getId())).start();
    }
}

二、线程生命周期的基本状态(State)

六种基本状态


NEW(新建)、RUNNABLE(可运行)、BLOCKED(阻塞):由锁导致的

WAITING(无限等待)、TIMED_WAITING(超时等待/限时等待)、TERMINATED(终止)

状态含义如何进入如何退出典型场景
新建New线程对象已经创建,但尚未启动通过new Thread()创建线程对象后调用线程的start()方法Thread thread = new Thread(Runnable);
可运行Runnable线程已启动,可能正在运行或正准备运行,等待CPU时间片调用start()方法;从阻塞、从等待或超时等待中准备好重新竞争CPU获取CPU时间片开始执行;或因某些操作让出CPU或进入其他状态等待操作系统调度执行
阻塞Blcoked线程因为尝试获取一个被其他线程持有的(synchroized)而未能成功尝试进入一个被其他线程持有的synchronized同步块或方法时当持有锁的线程释放锁,该线程便有机会获取锁并回到可运行状态竞争synchronized锁
等待Waiting线程进入无限期等待,需要等待线程显示唤醒调用Object.wait()、Thread.join()(无参)或LockSupport.park()被其他线程通过Object.notify()/notifyAll()或中断唤醒线程间协调,等待某个条件成立
超时等待Timed Waiting线程进入有限期等待,可在指定时间后自动唤醒或提前被唤醒调用Thread,sleep(long)、Object.wait(long)、Thread,join(long)等带超时参数的方法等待时间到期;或被其他线程通过中断、notify()等方式提前唤醒执行定时任务,或等待一段时间
终止Terminated线程执行完毕或因异常而结束run()方法正常执行结束;或执行过程中抛出了未捕获的异常终止是最终状态,无法再转换到其他状态任务完成

补充了解:

CPU时间片(Time Slice 或 Quantum)是分时操作系统分配给每个正在运行的进程或线程的一段极短的CPU时间。它是实现操作系统“同时”运行多个任务的关键机制。(此处的“同时”是一种假象)

获取方法


使用getState()方法可以获取线程的基本状态

代码示例:

public class ThreadStateDemo {
    private static final Object lock = new Object(); //用于同步的锁对象

    public static void main(String[] args) throws InterruptedException{
        //1.NEW 状态:线程刚被创建,未调用start()
        Thread newThread = new Thread();
        System.out.println("当前状态" + newThread.getState()); //此语句可输出当前线程状态

        //判断当前状态是否是NEW
        System.out.println("NEW状态:" + (newThread.getState() == Thread.State.NEW));

        //2.RUNNABLE 状态:线程启动后
        Thread runnableThread = new Thread(()->{
            while (!Thread.currentThread().isInterrupted()){
                //空转,保持线程Alive
            }
        });
        runnableThread.start(); //启动线程,线程启动后很快可能进入RUNNABLE状态
        Thread.sleep(1000); //休眠1秒,让线程启动

        //判断当前状态是否是RUNNABLE
        System.out.println("RUNNABLE状态:" + (runnableThread.getState() == Thread.State.RUNNABLE));

        //3.BLOCK 状态:由锁导致
        Thread blockThread = new Thread(()->{
            synchronized (lock){
                try {
                    Thread.sleep(1000); //持有锁一段时间,让另一个线程阻塞
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread willBeBlockedThread = new Thread(()->{
            //这个锁会尝试获取已被blockedThread持有的锁,从而进入BLOCKED状态
            synchronized (lock){
                System.out.println("willBeBlockedThread 获得了锁");
            }
        });

        blockThread.start();
        Thread.sleep(50); //确保blockedThread先启动并拿到锁
        willBeBlockedThread.start();
        Thread.sleep(50); //确保willBeBlockedThread已经开始并因获取不到锁而阻塞

        //判断当前状态是否是BLOCKED
        System.out.println("BLOCK 状态:" + (willBeBlockedThread.getState() == Thread.State.BLOCKED));

        //4.WAITING 状态:无期限等待
        Thread waitingThread = new Thread(()->{
            synchronized (lock){
                try {
                    lock.wait(); //调用wait()方法,释放锁并进入WAITING状态,de
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        waitingThread.start();
        Thread.sleep(3000); //确保waitingThread启动并进入WAITING状态

        //判断当前状态是否是WAITING
        System.out.println("WAITING状态:" + (waitingThread.getState() == Thread.State.WAITING));

        //唤醒waitingThread以便程序能够继续执行
        synchronized (lock){
            lock.notify();
        }

        //5.TIMED_WARNING 状态:显示等待
        Thread timedWaitingThread = new Thread(()->{
           try {
               Thread.sleep(2000); //睡眠2秒,进入TIMED_WAITING状态
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
        });
        timedWaitingThread.start();
        Thread.sleep(50); //确保timedWaitingThread启动并进入TIMED_WARNING状态

        //判断当前状态是否是TIMED_WAITING
        System.out.println("TIMED_WARNING状态:" + (timedWaitingThread.getState() == Thread.State.TIMED_WAITING));

        //6.TERMINATED 状态:线程终止)
        Thread terminatedThread = new Thread();
        terminatedThread.start();
        terminatedThread.join();

        //判断当前状态是否是TERMINATED
        System.out.println("TERMINATED状态:" + (terminatedThread.getState() == Thread.State.TERMINATED));

        //等待所有演示线程结束
        /**
         * join()方法是 Thread类提供的一个实例方法,
         * 它的核心作用是让当前线程(调用方)进入等待状态,直到目标线程(被调用方)执行完毕,
         * 或者等待超过指定的时间(如果使用了超时参数)。
         * 例如,在线程 A 的执行代码中调用了 threadB.join(),那么线程 A 会暂停下来,一直等到线程 B 运行结束,线程 A 才会继续执行后续代码
         * 。
         */
        blockThread.join();
        willBeBlockedThread.join();
        waitingThread.join();
        timedWaitingThread.join();
    }
}

结果:

三、获取和设置线程的名称(Name)

每个线程都有名称,默认格式为“Thread-" + 数字(例如 Thread-0,Thread-1)。

有两种方法:

1.构造方法:在创建线程时直接指定名称。

2.setName()方法:对已经创建的线程对象设置名称。

获取方法


使用getName()方法可以获取线程的名称

代码示例:

public class ThreadNamingDemo {
    public static void main(String[] args) throws InterruptedException{
        //方式1:通过Thread的构造方法设置线程名称(用Lambda表达式实现Runnable举例)
        Thread thread1 = new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "正在执行任务1");
        },"线程名称-1");

        //方式2:使用setName方法设置线程名称
        Thread thread2 = new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "正在执行任务2");
        });
        thread2.setName("线程名称-2");

        System.out.println("thread1的名称:" + thread1.getName()); //获取线程1的名称
        System.out.println("thread2的名称:" + thread2.getName()); //获取线程2的名称

        thread1.start();
        thread2.start();

        //获取当前线程(main线程)的名称
        System.out.println("mian方法所在线程名称:" + Thread.currentThread().getName()); //输出main
    }
}

结果:

四、查看是否存活(Alive)

线程存活指的是线程已经被启动(start()),并且还没有执行完 run() 方法中的任务,即线程还在“工作”中,没有“退休”

线程对象创建后(NEW 状态),但尚未调用 start()方法时,isAlive()返回 false。

调用 start()方法后,线程进入 RUNNABLE 状态,isAlive()返回 true。

线程的 run()方法执行完毕或线程因异常终止后(TERMINATED 状态),isAlive()返回 false。

获取方法


使用isAlive()方法可以获取线程是否存活的状态(true/false)

代码示例:

public class ThreadAliveDemo {
    public static void main(String[] args) throws InterruptedException{
        Thread thread = new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName() + "开始运行");
                Thread.sleep(2000); //休眠2秒
                System.out.println();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"测试线程");

        //线程未启动(现在是NEW状态)
        System.out.println("线程启动前是否存活:" + thread.isAlive()); //输出:false

        thread.start(); //启动线程,进入RUNNABLE状态

        //线程启动后(现在是RUNNABLE状态)
        System.out.println("线程启动后是否存活:" + thread.isAlive()); //输出:true

        Thread.sleep(3000); //休眠三秒,确认线程已经执行完毕

        System.out.println("线程运行结束后是否存活:" + thread.isAlive()); //输出:false
    }
}

结果:

五、优先级(Priority)

线程优先级为线程调度器提供提示,理论上优先级高的线程更易获得CPU时间。Java中优先级范围为1 (MIN_PRIORITY) 到10 (MAX_PRIORITY),默认为5 (NORM_PRIORITY)。

一定要在启动线程前设置优先级​​(调用start()方法前)

优先级仅为调度器提供建议,​​并不保证执行顺序​​,实际执行受操作系统和JVM实现影响

高优先级线程倾向于获得更多CPU时间,但不保证总是先执行。

设置方法


使用setPriority()方法可以设置代码优先级

获取方法


使用isPriority()方法可以获取代码优先级

代码示例:

public class ThreadPriorityDemo {
    private static void peformTask(){
        String threadName = Thread.currentThread().getName();
        int Priority = Thread.currentThread().getPriority();

        System.out.println(threadName + "启动 | 优先级:" + Priority);

        //模拟工作负载
        for (int i = 1; i <= 3; i++) {
            System.out.println(threadName + "执行步骤" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                System.out.println(threadName + "被中断");
                Thread.currentThread().interrupt();
                break;
            }
        }
        System.out.println(threadName + "完成");
    }
    public static void main(String[] args) {
        //打印线程默认优先级(一般是5)
        System.out.println(Thread.currentThread().getName() + "线程默认优先级为:" + Thread.currentThread().getPriority());

        Thread lowPriorityThread = new Thread(()->{
            Thread.currentThread().setName("低优先级线程");
            peformTask();
        });

        Thread highPriorityThread = new Thread(()->{
            Thread.currentThread().setName("高优先级线程");
            peformTask();
        });

        //设置优先级(1-10,数字越大优先级越高),必须在start()前就设置
        lowPriorityThread.setPriority(Thread.MIN_PRIORITY); //优先级1
        highPriorityThread.setPriority(Thread.MAX_PRIORITY); //优先级10

        lowPriorityThread.start();
        highPriorityThread.start();

    }
}

结果:

六、获取和设置后台程序(Daemon)

Java 中的线程分为​​前台线程​​和​​后台线程​​(也称为守护线程,Daemon Thread)

前台线程​​:会阻止 Java 进程结束,即使 main方法执行完毕,只要还有前台线程在运行,JVM 也不会退出。

后台线程:是为其他线程提供服务的线程(如 JVM 的垃圾回收线程)。它不会阻止 Java 进程结束。​​当所有前台线程都结束时,后台线程会自动死亡​​。而且它必须在start()方法之前使用

设置方法


使用setDaemon()方法可以设置线程的前后台。

setDaemon(true)是设置为后台线程;
setDaemon(false)是设置为前台线程。

获取方法


使用isDaemon()方法可以查看线程的前后台(true/false)

代码示例:

public class DaemonThreadDemo {
    public static void main(String[] args) throws InterruptedException{
        //创建一个无限循环的后台线程
        Thread daemonThread = new Thread(()->{
           while (true){
               System.out.println(Thread.currentThread().getName() + "后台线程 正在运行……");
               try {
                   Thread.sleep(1000); //每秒打印一次
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        },"后台线程示例");
        daemonThread.setDaemon(true); //必须在线程启动前设置为后台线程

        //创建一个只运行3秒的前台线程
        Thread userThread = new Thread(()->{
            for (int i = 1; i < 3; i++) {
                System.out.println(Thread.currentThread().getName() + "前台线程 运行了" + i + "秒" );
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"前台线程示例");

        System.out.println("daemonThread是否是后台线程" + daemonThread.isDaemon()); //输出:true
        System.out.println("userThread是否是后台线程" + userThread.isDaemon());  //输出:false

        daemonThread.start();
        userThread.start();

        userThread.join(); //主线程等待userThread执行完毕

        System.out.println(Thread.currentThread().getName() + "主线程结束");
        // 此时只有后台线程daemonThread还在运行,但因为它是后台线程,JVM会强制终止它,进程结束。
    }
}

结果:

七、中断(Interruption)

线程中断是一种​​协作机制​​,它允许一个线程通知另一个线程“你最好停下来”,但并不会强制立即终止目标线程。目标线程需要自行检查中断状态并决定如何响应。

这种机制提供了更大的灵活性,让线程有机会进行必要的清理工作,从而更安全地结束任务。

方法名所属类型功能描述是否会清楚中断状态标志
interrupt()非静态方法给线程一个中断标志设置中断状态为true,而不是停止线程。若线程正阻塞(如sleep),则会抛出InterruptedException异常
isInterrupted()非静态方法检查指定线程的中断状态(true/false)。
interrupted()静态方法检查当前线程的中断状态,并在检查后将中断状态清除为false

不同情况下 interrupt()方法的行为
线程状态或操作interrupt()的行为中断标志位变化注意事项
正常运行仅设置中断标志为true,线程不会停止,需要自行检查标志位。设置为true线程需主动检查isInterrupted()以响应中断
sleep()、wait()、join()抛出InterruptedException异常,并清除中断标志位(设为false)清除为false需在catch块中通常应恢复中断状态
LockSupport,park()线程会退出阻塞状态,不会抛出InterruptedException,但会保留中断标志保持为true适用于更底层的线程控制
同步阻塞(synchronized)不会响应中断,线程会继续等待锁无变化(仍为true,但在此场景下不直接起作用)需在获取锁后检查中断状态
I/O操作多数传统阻塞式I/O不响应中断无变化(设置为true,但操作本身不中断)需使用Java NIO的可中断通道机制

代码示例:

public class ThreadInterruptLambdaDemo {
    public static void main(String[] args) {
        //创建一个可中断的工作线程
        Thread workerThread = new Thread(()->{
            Thread.currentThread().setName("工作线程");
            System.out.println(Thread.currentThread().getName() + "开始工作");

            //检查中断状态,决定是否继续执行
            while (!Thread.currentThread().isInterrupted()){
                //若中断,则工作线程标记为true,不执行该while循环;若没有中断,则执行该while循环
                System.out.println("工作中……");
            }

            //退出循环后查看状态
            System.out.println("循环退出后的中断状态:" + Thread.currentThread().isInterrupted());

            //检查并清除中断状态
            System.out.println("第一次调用interrupted():" +Thread.interrupted()); //返回true并清除标记
            System.out.println("第二次调用interrupted():" +Thread.interrupted()); //再次调用,返回false

            System.out.println("线程自然结束");
        });

        workerThread.start();

        // 让主线程休眠1秒,确保工作线程能运行一段时间
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        workerThread.interrupt();
        System.out.println("主线程已发出中断信号");
    }
}

结果:

工作一会后

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值