Java多线程

96 阅读2分钟

如何停止一个正在运行的线程?

  • 使用标志位(flag):最安全和最推荐的方式是 使用一个共享变量作为标志位,通过改变这个标志位的值,来通知线程应该停止运行
    • 线程需要定期检查这个标志位,并在必要时退出
public class SafeStopThread implements Runnable {
    //这里使用了volatile关键字,确保变量的修改对所有线程可见
    private volatile boolean running = true;
    
    public void run() {
        while (running) {
            // 执行任务
        }
        // 清理资源
    }
    
    public void stopRunning() {
        running = false;
    }
}
  • 中断机制:Java提供中断机制,允许一个线程停止另一个线程的运行
    • 通过调用线程对象(Thread)的interrupt()方法,可以请求终止线程

中断机制的三个函数的解读

  • 调用Thread.interrupt()来中断一个线程,就会设置中断标识为 true
  • 当中断线程调用静态方法Thread.interrupted()来检查中断状态时,中断状态会被清零
  • 非静态方法isInterrupted()用来查询其它线程的中断状态,且不会改变中断状态标识

简单的说,就是任何抛出InterruptedException异常的方法,都会将中断状态清零

public class InterruptibleThread implements Runnable {
    
    public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                // 线程的工作逻辑
            }
        } catch (InterruptedException e) {
            // 处理中断异常,清理资源
            Thread.currentThread().interrupt(); // 保留中断状态
        }
    }
}
  • 避免使用stop()暴力停止:方法已弃用,强制让线程停止有可能使一些请理性的工作得不到完成

sleep和wait的区别?

特性sleep()wait()
所属类Thread 类(静态方法)Object 类(实例方法)
锁释放
使用前提任意位置调用必须在同步块内或同步方法内(持有锁)
唤醒机制超时自动恢复需 notify()/notifyAll() 或超时
设计用途暂停线程执行,不涉及锁协作线程间协调,释放锁让其他线程工作
  • 所属分类不同:sleep()可以在任何地方直接通过 Thread.sleep() 调用,无需依赖对象实例;wait()必须通过创建对象实例来调用
  • 锁释放的情况:在 sleep 期间,其他线程无法获得该线程持有的锁;Object.wait():调用该方法时,线程会释放持有的对象锁,进入等待状态,直到其它线程调用相同对象唤醒它
  • 唤醒机制:sleep 休眠时间结束后,线程 自动恢复 到就绪状态,等待CPU调度;wait 需要其他线程调用相同对象的 notify() 或 notifyAll() 方法才能被唤醒
    • notify() 会随机唤醒一个在该对象上等待的线程
    • notifyAll() 会唤醒所有在该对象上等待的线程