Java-多线程-线程状态

Java-多线程-线程状态

1 简介

Java线程并不是和Linux线程完全对等的,每个Java线程拥有NEW(新建)、RUNNABLE(就绪)、BLOCKED(阻塞)、WAITING(等待)、TIMED WAITING(计时等待)、TERMINATED(终止)。

Java线程调度属于抢占式调度,线程竞争CPU时间分片来执行,一个线程运行几十毫秒中就处于RUNNING状态,而时间片用完了被剥夺CPU资源又处于READY状态了,等待下次调度。

2 线程状态

在这里插入图片描述
在这里插入图片描述

  1. NEW(新建)
    使用 new Thread(new Runnable) 类或其子类建立一个线程对象后,该线程对象就处于新建状态。

    此时线程还未执行,一般是在构造方法中做一些初始化工作。

    NEW状态的线程只能在thread.start()方法之后转为RUNNABLE状态。

  2. RUNNABLE(就绪)
    NEW状态的线程调用了thread.start()方法之后,该线程就进入RUNNABLE状态,等待JVM里线程调度器的调度,此时处于READY就绪状态。

    当获得CPU时间片后,线程开始执行,线程处于RUNNING运行状态。时间片用完后,线程被剥夺运行资格,等待下一次运行,又变为就绪状态。也就是说,此状态下不能保证线程是就绪还是正在运行。

  3. BLOCKED(阻塞)
    RUNNABLE状态线程申请被其他线程持有的对象锁,此时就转为BLOCKED状态,此时线程不运行任何代码且消耗最少的资源,直到线程调度器重新激活运行该线程。

    当其他线程释放该对象锁后,如果本线程竞争到了对象锁,就转回RUNNABLE状态。

  4. WAITING(无期限等待)
    如果一个线程A等待另一个线程给与调度器一个条件时,线程A进入WAITING状态,等待被其他线程notify唤醒。

    如调用Object.waitThread.joinjava.util.concurrent中的Lock或Condition等。

    条件发生后,就转回RUNNABLE状态。(如果是wait方法进入的等待状态,被notify唤醒后进入对象锁同步队列重新竞争锁,竞争到了就进入RUNNABLE状态,竞争失败就进入BLOCKED状态)

  5. TIMED WAITING(计时等待)
    以上方法有一些带有时间参数的重载方法(如Object.waitThread.joinjava.util.concurrent中的Lock.tryLock、Condition.await),就会进入TIMED WAITING状态

     条件发生后,就转回`RUNNABLE`状态(如果是wait方法进入的等待状态,被notify唤醒后进入对象锁同步队列重新竞争锁,竞争到了就进入RUNNABLE状态,竞争失败就进入BLOCKED状态)。
    
  6. TERMINATED(终止)
    线程run方法结束或抛出了未捕获的异常导致结束。

    在一个TERMINATED的线程上调用start()方法会抛出java.lang.IllegalThreadStateException异常。

3 相关方法

  • Thread.sleep(long millis)
    由当前线程调用此方法,调用后进入TIMED_WAITING状态,但不释放对象锁。millis期满后线程自动唤醒进入RUNNABLE状态。

  • Thread.yield(),
    由当前线程调用此方法,给CPU提示表示当前线程愿意放弃获取的CPU时间片(调度器可忽略该提示),但不释放对象锁。如果成功释放时间片则该线程由运行状态变为就绪状态,由调度器再次选择线程进行调度执行。

    • Sleep对比Yield
      主要是使用场景不同。Sleep主要用来指定睡眠时间让出CPU,并在时间到后再被系统分配CPU资源,进行调度执行;而Yield是用来主动释放CPU给其他线程执行,但无法精确控制是否释放。
  • t.join()/t.join(long millis),
    join方法主要用来等待其他线程运行结束,再继续运行自己的线程代码。

    当前线程里调用其它线程t的join方法,当前线程进入WAITING/TIMED_WAITING状态,当前线程不会释放已经持有的对象锁。

    等到线程t执行完毕或者millis时间到,当前线程重新进入RUNNABLE状态。

  • obj.wait()
    当前线程调用对象的wait()方法,当前线程会释放该对象锁,并进入等待队列等待其他竞争到锁的线程执行完后唤醒,重新进入等待队列进行锁竞争,竞争成功后才会从wait方法返回。

    注意这个wait方法只会让该线程释放当前Object的对象锁,而不会放弃拥有的其他对象锁!

  • obj.wait(mills)
    当前线程调用对象的wait()方法,当前线程会释放该对象锁,并进入等待队列等待其他竞争到锁的线程执行完后唤醒或时间耗尽,重新进入等待队列进行锁竞争,竞争成功后才会从wait方法返回。

    注意这个wait方法只会让该线程释放当前Object的对象锁,而不会放弃拥有的其他对象锁!

  • obj.notify()
    该方法用来任意唤醒一个在对象锁的等待集的线程(其实看了源码会发现不是任意的,而是一个WaitQueue,FIFO)。

  • obj.notifyAll()
    唤醒在此对象Monitor上等待的所有线程。

4 线程优先级

很多操作系统都提供线程优先级的概念,但是由于平台特性的问题,Java中的线程优先级和不同平台中系统线程优先级并不匹配,所以Java线程优先级可以仅仅理解为“建议优先级”,通俗来说就是java.lang.Thread#setPriority(int newPriority)并不一定生效,有可能Java线程的优先级会被系统自行改变。

参考文档

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章