面试之线程状态

1.线程有哪些状态

1.1Java线程的六种状态

面试之线程状态_第1张图片

Java 线程六种状态

        

  • 新建

    • 当一个线程对象被创建,但还未调用 start 方法时处于新建状态

    • 此时未与操作系统底层线程关联

  • 可运行

    • 调用了 start 方法,就会由新建进入可运行

    • 此时与底层线程关联,由操作系统调度执行

  • 终结

    • 线程内代码已经执行完毕,由可运行进入终结

    • 此时会取消与底层线程关联

  • 阻塞

    • 当获取锁失败后,由可运行进入 Monitor 的阻塞队列阻塞,此时不占用 cpu 时间

    • 当持锁线程释放锁时,会按照一定规则唤醒阻塞队列中的阻塞线程,唤醒后的线程进入可运行状态

  • 等待

    • 当获取锁成功后,但由于条件不满足,调用了 wait() 方法,此时从可运行状态释放锁进入 Monitor 等待集合等待,同样不占用 cpu 时间

    • 当其它持锁线程调用 notify() 或 notifyAll() 方法,会按照一定规则唤醒等待集合中的等待线程,恢复为可运行状态

  • 有时限等待

    • 当获取锁成功后,但由于条件不满足,调用了 wait(long) 方法,此时从可运行状态释放锁进入 Monitor 等待集合进行有时限等待,同样不占用 cpu 时间

    • 当其它持锁线程调用 notify() 或 notifyAll() 方法,会按照一定规则唤醒等待集合中的有时限等待线程,恢复为可运行状态,并重新去竞争锁

    • 如果等待超时,也会从有时限等待状态恢复为可运行状态,并重新去竞争锁

    • 还有一种情况是调用 sleep(long) 方法也会从可运行状态进入有时限等待状态,但与 Monitor 无关,不需要主动唤醒,超时时间到自然恢复为可运行状态

其它情况(只需了解)

  • 可以用 interrupt() 方法打断等待有时限等待的线程,让它们恢复为可运行状态

  • park,unpark 等方法也可以让线程等待和唤醒

  • 当我们新建一个线程时,这个线程就会进入new新建状态。
  • 当我们去调用它的start方法时,线程从新建状态转换为runnable。
  • 在可运行状态下,多线程时可能会出现争抢锁的问题,当获取锁失败时,那么线程会从可运行状态进入blocked阻塞状态,暂停当前运行。如果再争抢锁成功了,就会从阻塞状态进入可运行状态。
  • 在可运行状态下,如果不满足某些条件导致程序不能正常执行,此时可以使用锁wait() 线程会从可运行状态进入waiting等待状态。
  • 当原线程满足条件后,可以在其他的线程中调用notify()来唤醒原线程或其他线程,唤醒后的线程会从waiting等待状态进入可运行状态
  • timed_waiting等待状态(有时限),当调用wait(long)方法时,跟wait()不同的时,它使用了一个long类型的参数,这个参数代表了等待的时间,当时间到期后,线程会继续执行从有时限等待进入可运行状态
  • 另一方面,有时限等待还可以通过sleep(long)方式来转换,同样也是当设定的时间到了之后,线程自动转换状态到可运行状态。
  • sleep(long)和wait(long)在这里的主要区别在于,sleep没有要求它需要满足什么条件,在语义上是我本身就像让这个线程进入等待状态。而wait往往是因为线程没有满足某些条件,比如资源没有分配够,而不得不进入到等待状态。
  • 当程序代码全部执行完毕后,线程就进入了terminated终结状态

1.2操作系统层面的五种状态

面试之线程状态_第2张图片

  • 运行态:分到 cpu 时间,能真正执行线程内代码的

  • 就绪态:有资格分到 cpu 时间,但还未轮到它的

  • 阻塞态:没资格分到 cpu 时间的

    • 涵盖了 java 状态中提到的阻塞等待有时限等待

    • 多出了阻塞 I/O,指线程在调用阻塞 I/O 时,实际由 I/O 设备完成,此时线程无事可做,只能干等

  • 新建与终结态:与 java 中同名状态类似,不再啰嗦

2.sleep和wait的异同

一个共同点,三个不同点

共同点

  • wait() ,wait(long) 和 sleep(long) 的效果都是让当前线程暂时放弃 CPU 的使用权,进入阻塞状态

不同点

  • 方法归属不同

    • sleep(long) 是 Thread 的静态方法

    • 而 wait(),wait(long) 都是 Object 的成员方法,每个对象都有

  • 醒来时机不同

    • 执行 sleep(long) 和 wait(long) 的线程都会在等待相应毫秒后醒来

    • wait(long) 和 wait() 还可以被 notify 唤醒,wait() 如果不唤醒就一直等下去

    • 它们都可以被打断唤醒

  • 锁特性不同(重点)

    • wait 方法的调用必须先获取 wait 对象的锁,而 sleep 则无此限制

    • wait 方法执行后会释放对象锁,允许其它线程获得该对象锁(我放弃 cpu,但你们还可以用)

    • 而 sleep 如果在 synchronized 代码块中执行,并不会释放对象锁(我放弃 cpu,你们也用不了)

你可能感兴趣的:(Java面试八股文,运维,java,面试)