• Thread之一:线程生命周期及六种状态


     《Thread之一:线程生命周期及五种状态

    Thread之二:sleep、wait、yield、join

     《juc线程池原理(四): 线程池状态介绍

    一、线程的生命周期及五种基本状态

    关于Java中线程的生命周期,首先看一下下面这张较为经典的图:

    上图中基本上囊括了Java中多线程各重要知识点。掌握了上图中的各知识点,Java中的多线程也就基本上掌握了。主要包括:

    Java线程具有七种基本状态

    新建状态(New):至今尚未启动的线程的状态。线程刚被创建,但尚未启动如:Thread t = new MyThread();

    就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

    运行状态(Running)当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就     绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

    无限期等待(Waiting):位于对象等待池中的阻塞状态(Blocked in object’s wait pool):当线程处于运行状态时,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中,这涉及到“线程通信”的内容。处于这种状态的线程不会被分配处理器执行时间,它们要等待被其他线程显示唤醒。以下方法会让线程陷入无限期的等待状态

    • 没有设置timeout参数的Object::wait()方法
    • 没有设置timeout参数的Thread::join()方法
    • LockSupport::park()方法

    限期等待(Timed Waiting)处于这种状态的线程也不会被分配处理器执行时间,不过无须等待其他线程显示唤醒,在一定时间后它们由系统自动唤醒。以下方法会让线程进入期限等待状态:

    • Thread::sleep()方法
    • 设置了timeout参数的Object::wait()方法
    • 设置了timeout参数的Thread::join()方法
    • LockSupport::parkNanos()方法
    • LockSupport::parkUntil()方法

    阻塞状态(Blocked):处于运行状态中的线程由于某种(当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中,这涉及到“线程同步”的内容。【线程在获取synchronized同步锁失败(因为锁被其它线程所占用)】)原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。 

     “阻塞状态”与“等待状态”的区别:“阻塞状态”在等待着获取一个排它锁,这个事件将在另一个线程放弃这个锁的时候发生;而“等待状态”则是在等待一段时间,或者唤醒动作发生。在程序进入同步区域的时候,线程就会进入阻塞状态。

    死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

    JVM线程运行状态 (JVM Thread Status)

    在 java.lang.Thread.State 中定义了线程的状态:

    NEW

    至今尚未启动的线程的状态。线程刚被创建,但尚未启动。

    RUNNABLE

    可运行线程的线程状态。线程正在JVM中执行,有可能在等待操作系统中的其他资源,比如处理器。

    BLOCKED

    受阻塞并且正在等待监视器的某一线程的线程状态。处于受阻塞状态的某一线程正在等待监视器锁,以便进入一个同步的块/方法,或者在调用 Object.wait 之后再次进入同步的块/方法。
    在Thread Dump日志中通常显示为 java.lang.Thread.State: BLOCKED (on object monitor) 。

    WAITING

    某一等待线程的线程状态。线程正在无期限地等待另一个线程来执行某一个特定的操作,线程因为调用下面的方法之一而处于等待状态:

    • 不带超时的 Object.wait 方法,日志中显示为 java.lang.Thread.State: WAITING (on object monitor)
    • 不带超时的 Thread.join 方法
    • LockSupport.park 方法,日志中显示为 java.lang.Thread.State: WAITING (parking)

    TIMED_WAITING

    指定了等待时间的某一等待线程的线程状态。线程正在等待另一个线程来执行某一个特定的操作,并设定了指定等待的时间,线程因为调用下面的方法之一而处于定时等待状态:

    • Thread.sleep 方法
    • 指定超时值的 Object.wait 方法
    • 指定超时值的 Thread.join 方法
    • LockSupport.parkNanos
    • LockSupport.parkUntil

    TERMINATED

    线程处于终止状态。

    根据Java Doc中的说明,在给定的时间上,一个只能处于上述的一种状态之中,并且这些状态都是JVM的状态,跟操作系统中的线程状态无关。

    JAVA虚拟机启动程序步骤:

    (1) Main是启动时候的主线程,即程序入口

    (2) 在main函数结束后,虚拟机会自动启动一个DestroyJavaVM线程,该线程会等待所有user thread 线程结束后退出(即,只剩下daemon 线程和DestroyJavaVM线程自己,整个虚拟机就退出,此时daemon线程被终止),因此,如果不希望程序退出,只要创建一个非daemon的子线程,让线程不停的sleep即可。

    线程的创建

    Thread类,有一个start方法,即启动该线程。 启动的线程会执行该类的run方法。注意:因为启动线程时要执行某个过程,因此,通常是需要重新实现run方法的

    线程的结束

    run模块执行完成主动退出,或者被其他线程强行终止。

    通过jstack pid >1.txt

    线程状态样例

    等待状态样例

     "IoWaitThread" prio=6 tid=0x0000000007334800 nid=0x2b3c waiting on condition [0x000000000893f000]
       java.lang.Thread.State: WAITING (parking)
                    at sun.misc.Unsafe.park(Native Method)
                    - parking to wait for  <0x00000007d5c45850> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
                    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
                    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
                    at java.util.concurrent.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:440)
                    at java.util.concurrent.LinkedBlockingDeque.take(LinkedBlockingDeque.java:629)
                    at com.nbp.theplatform.threaddump.ThreadIoWaitState$IoWaitHandler2.run(ThreadIoWaitState.java:89)
                    at java.lang.Thread.run(Thread.java:662) 
    

    上面例子中,IoWaitThread 线程保持等待状态并从 LinkedBlockingQueue 接收消息,如果 LinkedBlockingQueue 一直没有消息,该线程的状态将不会改变。

    阻塞状态样例

    "BLOCKED_TEST pool-1-thread-1" prio=6 tid=0x0000000006904800 nid=0x28f4 runnable [0x000000000785f000]
       java.lang.Thread.State: RUNNABLE
                    at java.io.FileOutputStream.writeBytes(Native Method)
                    at java.io.FileOutputStream.write(FileOutputStream.java:282)
                    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
                    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
                    - locked <0x0000000780a31778> (a java.io.BufferedOutputStream)
                    at java.io.PrintStream.write(PrintStream.java:432)
                    - locked <0x0000000780a04118> (a java.io.PrintStream)
                    at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
                    at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
                    at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:85)
                    - locked <0x0000000780a040c0> (a java.io.OutputStreamWriter)
                    at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:168)
                    at java.io.PrintStream.newLine(PrintStream.java:496)
                    - locked <0x0000000780a04118> (a java.io.PrintStream)
                    at java.io.PrintStream.println(PrintStream.java:687)
                    - locked <0x0000000780a04118> (a java.io.PrintStream)
                    at com.nbp.theplatform.threaddump.ThreadBlockedState.monitorLock(ThreadBlockedState.java:44)
                    - locked <0x0000000780a000b0> (a com.nbp.theplatform.threaddump.ThreadBlockedState)
                    at com.nbp.theplatform.threaddump.ThreadBlockedState$1.run(ThreadBlockedState.java:7)
                    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
                    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
                    at java.lang.Thread.run(Thread.java:662)
       Locked ownable synchronizers:
                    - <0x0000000780a31758> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
    "BLOCKED_TEST pool-1-thread-2" prio=6 tid=0x0000000007673800 nid=0x260c waiting for monitor entry [0x0000000008abf000]
       java.lang.Thread.State: BLOCKED (on object monitor)
                    at com.nbp.theplatform.threaddump.ThreadBlockedState.monitorLock(ThreadBlockedState.java:43)
                    - waiting to lock <0x0000000780a000b0> (a com.nbp.theplatform.threaddump.ThreadBlockedState)
                    at com.nbp.theplatform.threaddump.ThreadBlockedState$2.run(ThreadBlockedState.java:26)
                    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
                    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
                    at java.lang.Thread.run(Thread.java:662)
       Locked ownable synchronizers:
                    - <0x0000000780b0c6a0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
    "BLOCKED_TEST pool-1-thread-3" prio=6 tid=0x00000000074f5800 nid=0x1994 waiting for monitor entry [0x0000000008bbf000]
       java.lang.Thread.State: BLOCKED (on object monitor)
                    at com.nbp.theplatform.threaddump.ThreadBlockedState.monitorLock(ThreadBlockedState.java:42)
                    - waiting to lock <0x0000000780a000b0> (a com.nbp.theplatform.threaddump.ThreadBlockedState)
                    at com.nbp.theplatform.threaddump.ThreadBlockedState$3.run(ThreadBlockedState.java:34)
                    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886
                    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
                    at java.lang.Thread.run(Thread.java:662)
       Locked ownable synchronizers:
                    - <0x0000000780b0e1b8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
    

    在上面的例子中,BLOCKED_TEST pool-1-thread-1 线程占用了 <0x0000000780a000b0> 锁,然而 BLOCKED_TEST pool-1-thread-2 和 BLOCKED_TEST pool-1-thread-3 threads 正在等待获取锁。

    死锁状态样例

    "DEADLOCK_TEST-1" daemon prio=6 tid=0x000000000690f800 nid=0x1820 waiting for monitor entry [0x000000000805f000]
       java.lang.Thread.State: BLOCKED (on object monitor)
                    at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197)
                    - waiting to lock <0x00000007d58f5e60> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                    at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.monitorOurLock(ThreadDeadLockState.java:182)
                    - locked <0x00000007d58f5e48> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                    at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135)
    
       Locked ownable synchronizers:
                    - None
    
    "DEADLOCK_TEST-2" daemon prio=6 tid=0x0000000006858800 nid=0x17b8 waiting for monitor entry [0x000000000815f000]
       java.lang.Thread.State: BLOCKED (on object monitor)
                    at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197)
                    - waiting to lock <0x00000007d58f5e78> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                    at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.monitorOurLock(ThreadDeadLockState.java:182)
                    - locked <0x00000007d58f5e60> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                    at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135)
    
       Locked ownable synchronizers:
                    - None
    
    "DEADLOCK_TEST-3" daemon prio=6 tid=0x0000000006859000 nid=0x25dc waiting for monitor entry [0x000000000825f000]
       java.lang.Thread.State: BLOCKED (on object monitor)
                    at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.goMonitorDeadlock(ThreadDeadLockState.java:197)
                    - waiting to lock <0x00000007d58f5e48> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                    at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.monitorOurLock(ThreadDeadLockState.java:182)
                    - locked <0x00000007d58f5e78> (a com.nbp.theplatform.threaddump.ThreadDeadLockState$Monitor)
                    at com.nbp.theplatform.threaddump.ThreadDeadLockState$DeadlockThread.run(ThreadDeadLockState.java:135)
    
       Locked ownable synchronizers:
                    - None
    

    上面的例子中,当线程 A 需要获取线程 B 的锁来继续它的任务,然而线程 B 也需要获取线程 A 的锁来继续它的任务的时候发生的。在 thread dump 中,你能看到 DEADLOCK_TEST-1 线程持有 0x00000007d58f5e48 锁,并且尝试获取 0x00000007d58f5e60 锁。你也能看到 DEADLOCK_TEST-2 线程持有 0x00000007d58f5e60,并且尝试获取 0x00000007d58f5e78,同时 DEADLOCK_TEST-3 线程持有 0x00000007d58f5e78,并且在尝试获取 0x00000007d58f5e48 锁,如你所见,每个线程都在等待获取另外一个线程的锁,这状态将不会被改变直到一个线程丢弃了它的锁。

    无限等待的Runnable状态样例

    "socketReadThread" prio=6 tid=0x0000000006a0d800 nid=0x1b40 runnable [0x00000000089ef000]
       java.lang.Thread.State: RUNNABLE
                    at java.net.SocketInputStream.socketRead0(Native Method)
                    at java.net.SocketInputStream.read(SocketInputStream.java:129)
                    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
                    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
                    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
                    - locked <0x00000007d78a2230> (a java.io.InputStreamReader)
                    at sun.nio.cs.StreamDecoder.read0(StreamDecoder.java:107)
                    - locked <0x00000007d78a2230> (a java.io.InputStreamReader)
                    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:93)
                    at java.io.InputStreamReader.read(InputStreamReader.java:151)
                    at com.nbp.theplatform.threaddump.ThreadSocketReadState$1.run(ThreadSocketReadState.java:27)
                    at java.lang.Thread.run(Thread.java:662)
    

    上例中线程的状态是RUNNABLE,但在下面的堆栈日志中发现socketReadThread 线程正在无限等待读取 socket,因此不能单纯通过线程的状态来确定线程是否处于阻塞状态,应该根据详细的堆栈信息进行分析。

  • 相关阅读:
    2015抢票记事
    Provide your license server administrator with the following information.error code =-42,147
    微信支付现金红包接口
    SQL Server 触发器
    SQL增删查改注意的事项
    SQL while循环
    SQL SERVER 中is null 和 is not null 将会导致索引失效吗?
    HTML中head里的内容经浏览器解析后全到body里了
    sqLSERVER 计划缓存
    通用分页存储过程
  • 原文地址:https://www.cnblogs.com/duanxz/p/3733179.html
Copyright © 2020-2023  润新知