2024-03-23  阅读(1)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1839336608

Java 中的线程有如下六种状态:

  1. 新建(New): 当线程对象被创建后,它就处于新建状态。在这个状态下,线程还未开始执行。
  2. 可运行(Runnable): 调用线程的 start() 后,线程就进入可运行状态。
    1. 在这个状态下,线程可能正在运行,这时线程是运行中(Running)
    2. 也可能正在等待系统为其分配处理器资源,这时线程是就绪(Ready)
  3. 阻塞(Blocked): 当线程试图获取一个锁(synchronized资源)而该锁被其他线程持有时,则该线程进入阻塞状态。线程会在这个状态下等待,直到它可以获取到锁。
  4. 等待(Waiting): 当线程等待其他线程完成特定操作时,它会进入等待状态。例如,当线程调用 Object.wait()Thread.join()LockSupport.park() 时,它会进入这个状态。
  5. 超时等待(Timed Waiting): 这个状态与等待状态类似,但有时间限制。例如,当线程调用 Thread.sleep(long millis)Object.wait(long timeout)Thread.join(long millis)LockSupport.parkNanos()/parkUntil() 时,它会进入定时等待状态。
  6. 终止(Terminated): 当线程的 run() 方法执行完成后,它会进入终止状态。这意味着线程的任务已经结束了。

状态转换

几个方法的比较

  • Thread.sleep(long millis):当前线程调用该方法后,线程进入超时等TIMED_WAITING)状态,但不释放对象锁,millis后线程自动苏醒进入就绪状态Ready)。注意,该方法不会释放任何监视器(锁),如果一个线程持有锁,当它调用 sleep() 方法时,它仍然会保持对这些锁的持有。这意味着其他需要这些锁的线程可能会被阻塞,直到该线程醒来并释放锁。
  • Thread.yield():当前线程调用该方法后,线程会放弃获取的CPU时间片,但不释放锁资源,线程由运行状态Running)变为就绪状态Ready),让操作系统再次选择线程。它的作用是使当前正在执行的线程暂停执行,给其他同等优先级的线程执行的机会但并不保证一定会轮流执行,因为让步的线程还有可能被线程调度程序再次选中。Thread.yield()不会导致阻塞。该方法与sleep() 类似,只是不能由用户指定暂停多长时间
  • Thread.join()/Thread.join(long millis):当前线程里调用其它线程 Tjoin(),当前线程进入WAITING/TIMED_WAITING状态,当前线程不会释放已经持有的对象锁。线程T执行完毕或者millis时间到,当前线程一般情况下进入RUNNABLE状态,也有可能进入BLOCKED状态(因为join是基于wait实现的)。
  • Object.wait():当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列。依靠notify() / notifyAll()唤醒或者wait(long timeout) timeout时间到自动唤醒。需要注意的是Object.wait() 必须要在同步代码块或同步方法中调用,这意味着调用它的线程必须持有该对象的监视器锁。当一个线程调用 wait() 时,它会释放持有的监视器锁并进入等待状态,则其他线程就可以获取锁并执行同步的代码块或方法。
  • Object.notify():当一个线程调用 notify() 时,它会从这个对象的等待池中随机唤醒一个正在执行 wait() 方法的线程。被唤醒的线程会尝试重新获得监视器锁。一旦获得锁,它就可以继续执行。notifyAll() 唤醒是在此对象监视器上等待的所有线程。与 wait() 方法一样,notify() 也必须在同步代码块或同步方法中调用
  • LockSupport.park()/LockSupport.parkNanos(long nanos),LockSupport.parkUntil(long deadlines):该类方法用于阻塞当前线程,直到获得许可(permit)或者线程被中断。调用这类方法的线程进入WAITING/TIMED_WAITING状态。可以通过 LockSupport.unpark(Thread thread) 方法被唤醒。
    • LockSupport 使用一种许可(permit)机制。每个线程都有一个与之关联的许可,许可不能累积,它的数量只能是 0 或 1。
    • 如果一个线程已经拥有许可,那么park() 方法将立即返回,然后消耗这个许可。如果没有许可,park() 会阻塞线程。
    • 当调用 unpark() 时,会给指定线程发放一个许可(如果它之前没有许可的话),从而使得被 park() 阻塞的线程返回。

Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文