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

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()恢复线程运行
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值