线程状态

    xiaoxiao2021-03-26  28

    线程状态有:NEWRUNNABLEBLOCKEDWAITINGTIMED_WAITINGTERMINATED

    BLOCKED是等待获得对象锁

    WAITING是调用了wait, sleep, park

    sleep, 进入TIMED_WAITING状态,不出让锁

    wait, 进入TIMED_WAITING状态,出让锁,并进入对象的等待队列

    park, 进入WAITING状态,对比wait不需要获得锁就可以让线程WAITING,通过unpark唤醒

    interrupt, 只是给线程发个信号,如果在wait, sleep会收到exception

    yeild, 在操作系统层面让线程从running变成ready状态,等待继续被调度。在jvm的线程状态还是RUNNABLE

    1. 新建(new):新创建了一个线程对象。

    2. 可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。

    3. 运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。

    4. 阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种: 

    (一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。

    (二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。

    (三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。

    5. 死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

    在java锁的实现中,如果线程获取不到锁,会进入同步队列自旋,如果获取不到,则通过park方式进入到等待状态,进入等待状态后,依靠前驱节点出队或者被中断来唤醒,被唤醒后进入ready状态,通过自旋竞争锁,如果竞争到,出队,竞争不到,依然通过park方式等待。

    而获取到锁的线程,可以通过Object的wait/notify/notifyAll 或Lock的Condition的await/signal来进入等待/唤醒模式,这依靠将线程从同步队列首节点(只有同步队列的首节点才能获取到锁)转移到等待队列来实现,不同的是,Object的等待队列是一个,而Condition是多个,即同一个Lock可以new出多个condition,每个condition一个等待队列,在conditon的await方法中,是通过park方式来挂起线程的。同步队列首节点获取锁后,如果应用程序调用await,则线程进入到等待队列wait,并释放同步锁,然后唤醒同步队列的下一个节点。当其他线程调用signal时,等待队列的首节点会被加入到同步队列尾部并唤醒,然后竞争锁,不同的是signalAll方法,是对整个等待队列的节点操作,即所有等待队列的节点都会被移到同步队列然后唤醒。

    总结下,同步队列中是可以有资格获取锁的线程,其等待状态不依赖于外部事件,只要自旋过程中获取不到锁就会进入等待,而唤醒依赖于前驱节点释放锁。等待队列中的等待线程,是同步队列中,获取到锁的线程通过外部事件(调用wait方法)进入等待队列中的,其唤醒同样要依靠外部事件,唤醒后进入同步队列,要么获取到锁,要么等待获取锁。

    转载请注明原文地址: https://ju.6miu.com/read-663312.html

    最新回复(0)