美文网首页
JVM中线程的状态转换图

JVM中线程的状态转换图

作者: shoulda | 来源:发表于2018-05-31 14:51 被阅读0次

    线程在一定条件下,状态会发生变化。线程一共有以下几种状态:

    1.新建状态(new):新创建一个线程对象
    2.就绪状态(Runnable):线程对象创建后,其他线程调用该对象的star()方法,该状态的线程位于“可运行线程池”,变得可运行,只等待cpu的使用权。即在就绪状态的的进程除了cpu之外,其他的运行所需的资源都已全部获得。
    3.运行状态(Running):处于就绪状态的线程获取了cpu,执行程序代码
    4.阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃cpu使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

    阻塞的情况分三种

    (1)等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池”,进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒。
    (2)同步阻塞:运行的线程在获得对象的同步锁时,若该同步锁被别的线程占用,则jvm会把线程放入“锁池”中。
    (3)其他阻塞:运行sleep()或则join()方法,或者发出了I/0请求时,JVM会把该线程设置为阻塞状态,当sleep()状态超时时,join()等待线程终止或者超时,或则i/o处理完毕,线程重新转入就绪状态。
    5.死亡状态(dead):线程执行完了或则因异常退出run()方法,该线程结束生命周期。


    线程池.png

    拿到对象的锁标志,即为获得该对象(临界区)的使用权,即该线程或得了运行所需要的资源,进入“就绪状态”,只需获得cpu,就可以运行。因为当调用wait之后,线程会释放所有的锁资源,所以线程只有在获得此资源时才能进入就绪状态。

    以上状态转换图的详解

    1.线程的实现有两种方式,一种是继承Thread类,一种是实现runnable接口,但是不管怎么样,当我们newl了这个对象后,线程就进入初始状态;
    2.当对象调用了start()方法之后,线程进入就绪状态。
    3.进入就绪状态后,当对象被操作系统选中,获得cpu时间片就会进入运行状态;
    4.进入运行状态后情况就比较复杂了
    4.1.run()方法或main()方法结束后,线程就进入终止状态;
    4.2.当线程调用了自身的sleep()方法或则其他线程的join()方法,进程让出cpu,然后就会进入阻塞状态(该状态即停止当前线程,但并不释放所占有的资源即调用sleep()函数后,线程不会释放它的“锁标志”。)当sleep结束或则join()结束后,该线程进入可运行状态,继续等待OS分配cpu时间片,典型的,sleep()被用在等待某个资源就绪的情形。
    4.3 线程调用yield方法,意思是放弃当前获得的cpu时间片,回到就绪状态,这时与其他进程处于同等竞争状态,OS有可能会接着又让这个进程进入运行状态, 调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间片从而需要转到另一个线程。yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
    4.4当线程进入可运行状态时,发现将要调用的资源被synchronized(同步),获取不到锁标记,将会立即进入锁池状态,等待获取锁标记(这时的锁池里也许已经有了其他线程在等待获取锁标记,这时他们进入队列状态,即先到先得。)一旦线程获取了锁标记后,就转入就绪状态,等待os分配时间片。
    4.5suspend()和resume()方法,两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume() 被调用,才能使得线程重新进入可执行状态。典型地,suspend() 和 resume() 被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用 resume() 使其恢复。
    4.6wait()和notify()方法,当线程调用wait()方法后进入等待队列(进入这个状态会释放掉所占用的锁对象,),进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或者notifyAll()方法才能被唤醒(由于notify()只是唤醒一个线程,但我们由不能确定具体唤醒的是哪一个线程,也许我们需要唤醒的线程不能够被唤醒,因此在实际使用时,一般都用notifyAll()方法,唤醒有所线程),线程被唤醒后会进入锁池,等待获取锁标记。
    wait() 使得线程进入阻塞状态,它有两种形式:

    一种允许指定以毫秒为单位的一段时间作为参数;另一种没有参数。前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态即就绪状态,后者则必须对应的 notify()被调用。当调用wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。waite()和notify()因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronizedblock中进行调用。如果在non-synchronized函数或non-synchronizedblock中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。

    注意区别:初看起来wait()和notify()方法与suspend()和resume()方法没有什么区别,但是事实上他们是截然不同的,区别的核心在于,suspend()及其它所有方法在线程阻塞时都不会释放占用的锁,而wait() 和 notify() 这一对方法则相反。

    参考: http://www.blogjava.net/liver/archive/2009/06/04/279924.html
    参考:http://blog.csdn.net/peijunlin/article/details/3564559

    相关文章

      网友评论

          本文标题:JVM中线程的状态转换图

          本文链接:https://www.haomeiwen.com/subject/uxfqsftx.html