Java多线程基础 Thread类 常用方法

本文详细介绍了Java中Thread类的常用方法,如start、run、sleep、yield、join和interrupt,以及它们的使用场景、注意事项和线程状态管理。特别强调了不推荐使用的stop、suspend和resume方法及其替代方案。
摘要由CSDN通过智能技术生成

Java线程常用方法

方法名static说明注意
start()启动一个新线 程,在新的线程 运行 run 方法 中的代码start 方法只是让线程进入就绪,里面代码不一定立刻 运行(CPU 的时间片还没分给它)。每个线程对象的 start方法只能调用一次,如果调用了多次会出现 IllegalThreadStateException
run()新线程启动后会 调用的方法如果在构造 Thread 对象时传递了 Runnable 参数,则 线程启动后会调用 Runnable 中的 run 方法,否则默 认不执行任何操作。但可以创建 Thread 的子类对象, 来覆盖默认行为
join()等待线程运行结 束
join(long n)等待线程运行结 束,最多等待 n 毫秒
getId()获取线程长整型 的 idid 唯一
getName()获取线程名
setName(String)修改线程名
getPriority()获取线程优先级
setPriority(int)修改线程优先级java中规定线程优先级是1~10 的整数,较大的优先级 能提高该线程被 CPU 调度的机率
getState()获取线程状态Java 中线程状态是用 6 个 enum 表示,分别为: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
isInterrupted()判断是否被打断不会清除 打断标记
isAlive()线程是否存活 (还没有运行完 毕)
interrupt()打断线程如果被打断线程正在 sleep,wait,join 会导致被打断 的线程抛出 InterruptedException,并清除 打断标记 ;如果打断的正在运行的线程,则会设置 打断标记 ;park 的线程被打断,也会设置 打断标记
interrupted()static判断当前线程是 否被打断会清除 打断标记
currentThread()static获取当前正在执 行的线程
sleep(long n)static让当前执行的线 程休眠n毫秒, 休眠时让出 cpu 的时间片给其它 线程
yield()static提示线程调度器 让出当前线程对 CPU的使用主要是为了测试和调试

start 与 run

直接调用 run 是在主线程中执行了 run,没有启动新的线程

使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码

Thread t1 = new Thread("t1"){
    @Override
    public void run() {
        log.info(Thread.currentThread().getName());
    }
};
t1.run();
log.info("main end");
      

输出

18:20:15 [main] c - main
18:20:15 [main] c - main end 

程序仍在 main 线程运行

将 run 改为 start

Thread t1 = new Thread("t1"){
    @Override
    public void run() {
        log.info(Thread.currentThread().getName());
    }
};
t1.start();
log.info("main end");

输出

18:21:42 [main] c - main end
18:21:42 [t1] c - t1

程序在 t1 线程运行

start 只能调用一次 重复调用会抛出 IllegalThreadStateException

从start源码可以看到 线程状态 != 0 也就是新建状态 就会抛出 IllegalThreadStateException

image-20231016190134570

sleep 与 yield

sleep:

  • 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
  • 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
  • 睡眠结束后的线程未必会立刻得到执行
  • 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性

yield:

  • 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程
  • 具体的实现依赖于操作系统的任务调度器
Runnable task1 = () -> {
    while (true) {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
};
Runnable task2 = () -> {
    while (true) {
        Thread.yield();
    }
};
Thread t1 = new Thread(task1, "t1");
Thread t2 = new Thread(task2, "t2");
t2.start();
t1.start();
System.out.println("t2 线程状态" + t2.getState());
System.out.println("t1 线程状态" + t1.getState());

可以看到线程调用 sleep会状态转为阻塞 ,调用yield 后转为就绪。

差别就是 Thread.yield()会让出CPU资源,但不进入休眠状态,而是等待线程调度器重新选择它。,Thread.sleep()会进入休眠状态,不占用CPU资源,而在指定时间后自动唤醒。

image-20231016191537226.

join 方法详解

join() 是 Java 多线程编程中一个非常重要的方法,它允许一个线程等待另一个线程完成后再继续执行。下面是对 join() 方法的详细解释:

  1. 功能:
    join() 方法用于让一个线程等待另一个线程完成。当一个线程调用另一个线程的 join() 方法时,它将暂停自己的执行,直到被等待的线程执行完毕。这通常用于协调线程的执行顺序,确保在某个线程完成后再执行另一个线程。

  2. 异常:
    join() 方法声明了可能抛出 InterruptedException 异常,这是因为线程可以被中断。如果等待的线程在等待时被中断,join() 方法会抛出 InterruptedException 异常。

  3. 重载方法:
    join() 还有一个重载方法,可以指定等待的时间,如下所示:

    public final synchronized void join(long millis) throws InterruptedException
    public final synchronized void join(long millis, int nanos) throws InterruptedException
    

    这些重载方法允许你等待一段指定的时间,如果等待的时间超过了指定时间,线程将会继续执行。

  4. 使用示例:
    下面是一个简单的示例,演示如何使用 join() 方法:

    	public static void main(String[] args) {
            Thread thread1 = new Thread(() -> {
                for (int i = 1; i <= 5; i++) {
                    Thread.sleep(10);
                    System.out.println("Thread 1: " + i);
                }
            });
    
            Thread thread2 = new Thread(() -> {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("Thread 2: " + i);
                }
            });
    
            thread1.start();
            try {
                thread1.join(); // 主线程等待 thread1 执行完
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            thread2.start();
        }
    

    输出

    Thread 1: 1
    Thread 1: 2
    Thread 1: 3
    Thread 1: 4
    Thread 1: 5
    Thread 2: 1
    Thread 2: 2
    Thread 2: 3
    Thread 2: 4
    Thread 2: 5
    

    在上述示例中,主线程启动了 thread1,然后调用 thread1.join(),这会使主线程等待 thread1 执行完毕。然后,主线程再启动 thread2

修改 thread1.join() -> thread1.join(25)

输出

主线程启动了 thread1,然后调用 thread1.join(25),这会使主线程等待 thread1 执行25ms。然后,主线程启动 thread2

Thread 1: 1
Thread 1: 2
Thread 2: 1
Thread 2: 2
Thread 2: 3
Thread 2: 4
Thread 2: 5
Thread 1: 3
Thread 1: 4
Thread 1: 5

interrupt 方法详解

interrupt() 方法是 Java 多线程编程中用于中断线程的方法。它允许一个线程通知另一个线程,请求它终止执行或进行一些其他处理。下面是 interrupt() 方法的详细解释:

  1. 功能:
    interrupt() 方法用于中断一个线程,即通知目标线程中断它的执行。线程可以通过检查其中断状态来响应中断请求,并根据需要采取适当的措施。中断并不直接停止线程的执行,它只是发送一个中断请求。

  2. 中断状态:

    • 每个线程都有一个中断状态,它是一个布尔值,默认为 false
    • 调用 interrupt() 方法会将目标线程的中断状态设置为 true
    • 可以使用 Thread.isInterrupted() 方法来检查线程的中断状态,或者使用 Thread.interrupted() 静态方法来检查当前线程的中断状态。
  3. 响应中断:

    • 当一个线程被中断时,它可以根据需要采取不同的行动,如终止线程、抛出 InterruptedException 异常或继续执行。响应中断的方式取决于线程的设计和需求。
    • 典型的响应中断方式包括检查中断状态并做相应处理,如退出循环或释放资源。
  4. InterruptedException 异常:

    • 在某些情况下,线程可能会调用会抛出 InterruptedException 异常的方法,如 Object.wait(), Thread.sleep(), 和 BlockingQueue.take()
    • 当一个线程被中断时,这些方法可能抛出 InterruptedException 异常,通常用于指示线程应该终止执行。
  5. 使用示例:

    public class InterruptExample {
        public static void main(String[] args) {
            Thread worker = new Thread(() -> {
                while (!Thread.currentThread().isInterrupted()) {
                    System.out.println("Working...");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        System.out.println("Thread interrupted while sleeping.");
                        // 清除中断状态
                        Thread.currentThread().interrupt(); // 重新设置中断状态
                    }
                }
                System.out.println("Worker thread exiting.");
            });
    
            worker.start();
    
            // 主线程等待一段时间后中断 worker 线程
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            worker.interrupt(); // 中断 worker 线程
        }
    }
    
    // 输出
    Working...
    Working...
    Working...
    Working...
    Working...
    Thread interrupted while sleeping.
    Worker thread exiting.
    

    在上述示例中,worker 线程在一个循环中执行工作,它会检查自己的中断状态,如果被中断,则退出循环。主线程在启动 worker 线程后等待一段时间,然后调用 interrupt() 方法来中断 worker 线程的执行。

interrupt 打断阻塞状态的线程和正常运行的线程区别:

  1. 阻塞状态的线程:

    当一个线程处于阻塞状态(如调用Object.wait(), Thread.sleep(), BlockingQueue.take()等方法时)并且被调用了interrupt()方法,会出现以下情况:

    • 线程会抛出InterruptedException异常:这是Java标准库的多个阻塞方法的一种通用行为,以通知线程被中断。
    • 线程的中断状态被清除:interrupted()方法返回trueisInterrupted()方法返回true,但是线程的中断状态会被重置为false

    阻塞状态的线程通常会捕获InterruptedException异常,然后根据需要采取适当的处理。这可以包括释放资源、终止线程或继续执行,具体取决于线程的设计和需求。

  2. 正常运行的线程:

    当一个线程处于正常运行状态(没有被阻塞),并且被调用了interrupt()方法,会出现以下情况:

    • 线程不会立即停止:interrupt()方法仅仅是将线程的中断状态设置为true
    • 线程需要显式检查中断状态:线程在适当的地方需要主动检查自身的中断状态,然后根据需要决定是否终止执行。

    正常运行的线程需要在代码中显式检查中断状态,通常使用Thread.isInterrupted()方法或Thread.interrupted()方法(后者会清除中断状态)来检查线程的中断状态,并在适当的时候决定终止执行。这可以是通过抛出InterruptedException来终止线程,或者通过采取其他终止操作。

打断正常运行的线程 如果不检测自身的中断状态是没效果的

Thread t1 = new Thread
    for (int i = 0; i 
        System.out.pri
    }
});
t1.start();
t1.interrupt();

// 输出
0
1
2
3
4 

使用interrupted判断 会清除打断标记

Thread t1 = new Thread(() -> {						
    for (int i = 0; i < 5; i++) {						
        // 会清除打断标记
        if (!Thread.interrupted()){						
            System.out.println(i);						
        }else {														
            System.out.println("中断处理");						
        }
    }
});
t1.start();
t1.interrupt();
// 输出
中断处理 // 因为中断标记被清除 所以中断处理只会有一次
1
2
3
4
Thread t1 = new Thread(() -> {
    for (int i = 0; i < 5; i++) {
        // 不会清除打断标记
        if (!Thread.currentThread().isInterrupted()){
            System.out.println(i);
        }else {
            System.out.println("中断处理");
        }
    }
});
t1.start();
t1.interrupt();
// 输出
中断处理
中断处理
中断处理
中断处理
中断处理

不推荐使用的方法

方法名static作用说明
stop()停止线程运行这个方法被弃用,因为它会强制终止线程,可能导致资源泄漏和不一致的程序状态。取而代之,应该使用更安全的方式来协调线程的停止,例如通过设置一个标志,使线程自行停止。
suspend()挂起(暂停)线程运行Thread.suspend()Thread.resume() 方法:这两个方法也已被弃用,因为它们可能导致线程死锁或其他问题。建议使用更安全的线程挂起和恢复机制,例如 wait()notify() 或使用高级并发库中的工具。
resume()恢复线程运行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值