学习java线程状态和看懂thread dump文件中的线程信息

线程的状态是一个很重要的东西,因此thread dump中会显示这些状态,通过对这些状态的分析,能够得出线程的运行状况,进而发现可能存在的问题。线程的状态在Thread.State这个枚举类型中定义:

 public enum State
 {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
}

下面简单地介绍下这几个状态值:

1、NEW:

我们知道每一个线程,在堆内存中都有一个对应的Thread对象。Thread t = new Thread();当刚刚在堆内存中创建Thread对象,还没有调用t.start()方法之前,线程就处在NEW状态。在这个状态上,线程与普通的java对象没有什么区别,就仅仅是一个堆内存中的对象。

2、RUNNABLE

该状态表示线程具备所有运行条件,在运行队列中准备操作系统的调度,或者正在运行。 这个状态的线程比较正常,但如果线程长时间停留在在这个状态就不正常了,这说明线程运行的时间很长(存在性能问题),或者是线程一直得不得执行的机会(存在线程饥饿的问题)。

3、BLOCKED

线程正在等待获取java对象的监视器(也叫内置锁),即线程正在等待进入由synchronized保护的方法或者代码块。synchronized用来保证原子性,任意时刻最多只能由一个线程进入该临界区域,其他线程只能排队等待。

4、WAITING

处在该线程的状态,正在等待某个事件的发生,只有特定的条件满足,才能获得执行机会。而产生这个特定的事件,通常都是另一个线程。也就是说,如果不发生特定的事件,那么处在该状态的线程一直等待,不能获取执行的机会。比如说,A线程调用了obj对象的obj.wait()方法,如果没有线程调用obj.notify或obj.notifyAll,那么A线程就没有办法恢复运行;如果A线程调用了LockSupport.park(),没有别的线程调用LockSupport.unpark(A),那么A没有办法恢复运行。

5、TIMED_WAITING

我们知道J.U.C中很多与线程相关类,都提供了限时版本和不限时版本的API。TIMED_WAITING意味着线程调用了限时版本的API,正在等待时间流逝;当等待时间过去后,线程一样可以恢复运行。如果线程进入了WAITING状态,一定要特定的事件发生才能恢复运行;而处在TIMED_WAITING的线程,如果特定的事件发生或者是时间流逝完毕,都会恢复运行。

6、TERMINATED

线程执行完毕,执行完run方法正常返回,或者抛出了运行时异常而结束,线程都会停留在这个状态。这个时候线程只剩下Thread对象了,没有什么用了。

接下来我们利用JDK提供的jstack工具,查看下thread dump文件中线程的状态。NEW、RUNNABLE、TERMINATED这3个状态很容易理解,主要讲下其它3种状态。

1、显示BLOCKED状态

package jstack;

public class BlockedState
{
	private static Object object = new Object();

	public static void main(String[] args)
	{
		Runnable task = new Runnable() {

			@Override
			public void run()
			{
				synchronized (object)
				{
					long begin = System.currentTimeMillis();

					long end = System.currentTimeMillis();

					// 让线程运行5分钟,会一直持有object的监视器
					while ((end - begin) <= 5 * 60 * 1000)
					{

					}
				}
			}
		};

		new Thread(task, "t1").start();
		new Thread(task, "t2").start();
	}
}

先获取object的线程会执行5分钟,这5分钟内会一直持有object的监视器,另一个线程无法执行处在BLOCKED状态

C:\Documents and Settings\Administrator>jps
5400 Jps
3364
4752 BlockedState

C:\Documents and Settings\Administrator>jstack 4752
2014-09-23 19:42:28
Full thread dump Java HotSpot(TM) Server VM (20.12-b01 mixed mode):

"DestroyJavaVM" prio=6 tid=0x00856c00 nid=0x1314 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"t2" prio=6 tid=0x27d7a800 nid=0x1350 waiting for monitor entry [0x2833f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at jstack.BlockedState$1.run(BlockedState.java:17)
        - waiting to lock <0x1cfcdc00> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:662)

"t1" prio=6 tid=0x27d79400 nid=0x1338 runnable [0x282ef000]
   java.lang.Thread.State: RUNNABLE
        at jstack.BlockedState$1.run(BlockedState.java:22)
        - locked <0x1cfcdc00> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:662)

通过thread dump可以看到:t2线程确实处在BLOCKED (on object monitor)。waiting for monitor entry 等待进入synchronized保护的区域。

2、显示WAITING状态

package jstack;

public class WaitingState
{
	private static Object object = new Object();

	public static void main(String[] args)
	{
		Runnable task = new Runnable() {

			@Override
			public void run()
			{
				synchronized (object)
				{
					long begin = System.currentTimeMillis();

					long end = System.currentTimeMillis();

					// 让线程运行5分钟,会一直持有object的监视器
					while ((end - begin) <= 5 * 60 * 1000)
					{
						try
						{
							// 进入等待的同时,会进入释放监视器
							object.wait();
						} catch (InterruptedException e)
						{
							e.printStackTrace();
						}
					}
				}
			}
		};

		new Thread(task, "t1").start();
		new Thread(task, "t2").start();
	}
}
C:\Documents and Settings\Administrator>jps
3356 Jps
3364
5784 WaitingState

C:\Documents and Settings\Administrator>jstack 5784
2014-09-23 19:48:43
Full thread dump Java HotSpot(TM) Server VM (20.12-b01 mixed mode):

"DestroyJavaVM" prio=6 tid=0x00856c00 nid=0x1734 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"t2" prio=6 tid=0x27d7e000 nid=0x17f4 in Object.wait() [0x2833f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x1cfcdc00> (a java.lang.Object)
        at java.lang.Object.wait(Object.java:485)
        at jstack.WaitingState$1.run(WaitingState.java:26)
        - locked <0x1cfcdc00> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:662)

"t1" prio=6 tid=0x27d7d400 nid=0x17f0 in Object.wait() [0x282ef000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x1cfcdc00> (a java.lang.Object)
        at java.lang.Object.wait(Object.java:485)
        at jstack.WaitingState$1.run(WaitingState.java:26)
        - locked <0x1cfcdc00> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:662)

可以发现t1和t2都处在WAITING (on object monitor),进入等待状态的原因是调用了in Object.wait()。通过J.U.C包下的锁和条件队列,也是这个效果,大家可以自己实践下。

3、显示TIMED_WAITING状态

package jstack;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TimedWaitingState
{
	// java的显示锁,类似java对象内置的监视器
	private static Lock lock = new ReentrantLock();

	// 锁关联的条件队列(类似于object.wait)
	private static Condition condition = lock.newCondition();

	public static void main(String[] args)
	{
		Runnable task = new Runnable() {

			@Override
			public void run()
			{
				// 加锁,进入临界区
				lock.lock();

				try
				{
					condition.await(5, TimeUnit.MINUTES);
				} catch (InterruptedException e)
				{
					e.printStackTrace();
				}

				// 解锁,退出临界区
				lock.unlock();
			}
		};

		new Thread(task, "t1").start();
		new Thread(task, "t2").start();
	}
}
C:\Documents and Settings\Administrator>jps
5952 Jps
3364
5732 TimedWaitingState

C:\Documents and Settings\Administrator>jstack 5732
2014-09-23 19:59:44
Full thread dump Java HotSpot(TM) Server VM (20.12-b01 mixed mode):

"DestroyJavaVM" prio=6 tid=0x00856c00 nid=0x169c waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"t2" prio=6 tid=0x27d7d800 nid=0xc30 waiting on condition [0x2833f000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x1cfce5b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2116)
        at jstack.TimedWaitingState$1.run(TimedWaitingState.java:28)
        at java.lang.Thread.run(Thread.java:662)

"t1" prio=6 tid=0x280d0c00 nid=0x16e0 waiting on condition [0x282ef000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x1cfce5b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2116)
        at jstack.TimedWaitingState$1.run(TimedWaitingState.java:28)
        at java.lang.Thread.run(Thread.java:662)

可以看到t1和t2线程都处在java.lang.Thread.State: TIMED_WAITING (parking),这个parking代表是调用的JUC下的工具类,而不是java默认的监视器。内置锁和显示锁的差别,可以看我下java并发相关的文章  java并发编程专题
 http://blog.csdn.net/aitangyong/article/category/2298385

接下来看下thread dump打印出的线程信息代表什么含义,每个线程的基本都是一样的,我们随便选取一个,分析下:

"t1" prio=6 tid=0x27d7d400 nid=0x17f0 in Object.wait() [0x282ef000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x1cfcdc00> (a java.lang.Object)
        at java.lang.Object.wait(Object.java:485)
        at jstack.WaitingState$1.run(WaitingState.java:26)
        - locked <0x1cfcdc00> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:662)

t1 : 这个是线程名称,可以在new Thread()对象的时候指定,或者调用Thread.setName。有了这个名称,搜索thread dump的时候更加方便。这也就是为什么,一般创建线程的时候需要指定线程名称,而不是使用默认的名称。

prio=6 : 这个代表的是线程的优先级priority,也可以通过Thread类中的API修改。实际应用中,一般不会设置该属性,没有太大的用处。

tid : Java的线程Id (这个线程在当前虚拟机中的唯一标识)。

nid : 线程本地标识,是线程在操作系统中的标识。

[0x282ef000] : 对象的内存地址,通过JVM内存查看工具,能够看出线程是在哪儿个对象上等待。

java.lang.Thread.State: WAITING (on object monitor) : 显示线程当前时刻的状态,括号里面是处于该状态的原因。

最下面以at开头的是线程的调用堆栈,通过它可以看出线程执行代码的流程。

最后我们看下dump文件中Waiting for monitor entry 和 in Object.wait()的区别。首先我们需要注意一点:这2个东西都是针对Object对象的监视器而言的,只要监视器才会有这种区分,因为监视器是JVM内置支持的,所以可以想象的到,JVM内部会特殊处理这个监视器。而JDK5.0之后提供显示锁Lock不不会区分这2种状态,因为Lock对于JVM而言,就是一个普通的java对象。下面这个图,描述了线程和
Monitor之间关系,以及线程的状态转换图:

从图中可以看出,每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait
Set”里面等候。在 “Entry Set”中等待的线程状态是 “Waiting for monitor entry”,而在 “Wait Set”中等待的线程状态是 “in Object.wait()”。 简单地理解:“Entry Set”中存放的是等待进入synchronized的线程,“Wait
Set”中存放的是已经进入了synchronized但是调用了object.wait的线程。

时间: 2024-10-10 15:11:23

学习java线程状态和看懂thread dump文件中的线程信息的相关文章

jstack Dump日志文件中的线程状态

jstack Dump 日志文件中的线程状态 dump 文件里,值得关注的线程状态有: 死锁,Deadlock(重点关注)  执行中,Runnable 等待资源,Waiting on condition(重点关注) 等待获取监视器,Waiting on monitor entry(重点关注) 暂停,Suspended 对象等待中,Object.wait() 或 TIMED_WAITING 阻塞,Blocked(重点关注)   停止,Parked 下面我们先从第一个例子开始分析,然后再列出不同线程

[JAVA]JAVA章3 如何获取及查看DUMP文件

一.dump基本概念 在故障定位(尤其是out of memory)和性能分析的时候,经常会用到一些文件来帮助我们排除代码问题.这些文件记录了JVM运行期间的内存占用.线程执行等情况,这就是我们常说的dump文件.常用的有heap dump和thread dump(也叫javacore,或java dump).我们可以这么理解:heap dump记录内存信息的,thread dump是记录CPU信息的. heap dump: heap dump文件是一个二进制文件,它保存了某一时刻JVM堆中对象

《Java虚拟机原理图解》6、 class文件中的方法表集合--method方法在class文件中是怎样组织的

0. 前言 了解JVM虚拟机原理是每一个Java程序员修炼的必经之路.但是由于JVM虚拟机中有很多的东西讲述的比较宽泛,在当前接触到的关于JVM虚拟机原理的教程或者博客中,绝大部分都是充斥的文字性的描述,很难给人以形象化的认知,看完之后感觉还是稀里糊涂的. 感于以上的种种,我打算把我在学习JVM虚拟机的过程中学到的东西,结合自己的理解,总结成<Java虚拟机原理图解> 这个系列,以图解的形式,将抽象的JVM虚拟机的知识具体化,希望能够对想了解Java虚拟机原理的的Java程序员 提供点帮助.

一文看懂非标业务中的收益权

来源:图解金融 目录 - - - - - 1. 法律法规及监管规范有关“收益权”的规定 2. 非标业务中的收益权交易实践及其法律特征 3. 收益权的法律性质及其交易的法律后果 4. 结语 作者按:自银监会“2013年8号文”首次提出以来,“非标”概念始终在银行业金融监管中扮演着重要角色.2018年颁布的<关于规范金融机构资产管理业务的指导意见>,更将“非标”的适用范围正式扩展至全金融业务领域.究其概念不断发展壮大的原因,“非标”业务在交易主体.交易标的.清算交割.交易信息公开等方面都不受“场内

《Java虚拟机原理图解》1.4 class文件中的字段表集合--field字段在class文件中是怎样组织的

0.前言 了解JVM虚拟机原理是每一个Java程序员修炼的必经之路.但是由于JVM虚拟机中有很多的东西讲述的比较宽泛,在当前接触到的关于JVM虚拟机原理的教程或者博客中,绝大部分都是充斥的文字性的描述,很难给人以形象化的认知,看完之后感觉还是稀里糊涂的. 感于以上的种种,我打算把我在学习JVM虚拟机的过程中学到的东西,结合自己的理解,总结成<Java虚拟机原理图解> 这个系列,以图解的形式,将抽象的JVM虚拟机的知识具体化,希望能够对想了解Java虚拟机原理的的Java程序员 提供点帮助. 读

Java虚拟机原理图解-- 1.2、class文件中的常量池

了解JVM虚拟机原理 是每一个Java程序员修炼的必经之路.但是由于JVM虚拟机中有很多的东西讲述的比较宽泛,在当前接触到的关于JVM虚拟机原理的教程或者博客中,绝大部分都是充斥的文字性的描述,很难给人以形象化的认知,看完之后感觉还是稀里糊涂的.感于以上的种种,我打算把我在学习JVM虚拟机的过程中学到的东西,结合自己的理解,总结成<Java虚拟机原理图解> 这个系列,以图解的形式,将抽象的JVM虚拟机的知识具体化,希望能够对想了解Java虚拟机原理的的Java程序员 提供点帮助. 上一章节&l

《Java虚拟机原理图解》 2、class文件中的常量池

了解JVM虚拟机原理 是每一个Java程序员修炼的必经之路.但是由于JVM虚拟机中有很多的东西讲述的比较宽泛,在当前接触到的关于JVM虚拟机原理的教程或者博客中,绝大部分都是充斥的文字性的描述,很难给人以形象化的认知,看完之后感觉还是稀里糊涂的.感于以上的种种,我打算把我在学习JVM虚拟机的过程中学到的东西,结合自己的理解,总结成<Java虚拟机原理图解> 这个系列,以图解的形式,将抽象的JVM虚拟机的知识具体化,希望能够对想了解Java虚拟机原理的的Java程序员 提供点帮助. 上一章节&l

java将已有的字符串保存到txt文件中

python网络爬虫-通过互联网采集 RMQ算法的学习(区间最值问题)NYOJ119士兵杀敌(三) JAVA常用设计模式 Java多线程知识要点 9fw谀泄牡http://p.baidu.com/itopic/main/center?uid=15fe616263346630323931e4ac&qizj夹餐智p7k9e6律犹媒http://p.baidu.com/itopic/main/center?uid=6bfe616263386334303438e5ac&8q90潦卓嚷v5uuq9轮

透过现象看webpack处理css文件中图片路径转换的具体过程

webpack是目前使用比较流行的一个前端模块打包器,前端的任何资源都被当成一个模块来处理,如图片.css文件等等.在基于webpack构建的前端项目中,一般都会配置有关css文件处理的规则,这其中也包括css文件中图片资源的处理,那么webpack到底是怎么处理它的呢?笔者之前也遇到过类似图片路劲的问题,为此还写过一篇博文webpack生成的css文件background-image url图片无法加载.今天就来说说webpack是怎么处理css文件中的图片路径的,首先上一个具体的例子. 一个