获取进程号html
使用命令:jpsjava
经常使用参数:c++
-m 输出传递给main方法的参数,若是是内嵌的JVM则输出为null。安全
-l 输出应用程序主类的完整包名,或者是应用程序JAR文件的完整路径。框架
-v 输出传给JVM的参数。jvm
示例:ide
线程栈的获取
工具
使用命令:jstack,一般使用管道将信息输出到文件,便于分析
性能
经常使用参数:优化
-F 当jstack没有响应的时候强制打印栈信息。
-l 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表。
-m 打印java和native c/c++框架的全部栈信息。
示例:
线程栈内容示例
2016-03-07 18:04:57 Full thread dump Java HotSpot(TM) Client VM (24.80-b11 mixed mode): "Attach Listener" daemon prio=10 tid=0xb7675000 nid=0x4a9 waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Service Thread" daemon prio=10 tid=0xb766ec00 nid=0x44a runnable [0x00000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "C1 CompilerThread0" daemon prio=10 tid=0xb766d000 nid=0x449 waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Signal Dispatcher" daemon prio=10 tid=0xb766b400 nid=0x448 runnable [0x00000000] java.lang.Thread.State: RUNNABLE Locked ownable synchronizers: - None "Finalizer" daemon prio=10 tid=0xb765ac00 nid=0x447 in Object.wait() [0xa14ad000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0xa1a04750> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135) - locked <0xa1a04750> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209) Locked ownable synchronizers: - None "Reference Handler" daemon prio=10 tid=0xb7659400 nid=0x446 in Object.wait() [0xa14fe000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0xa1a043b8> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:503) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133) - locked <0xa1a043b8> (a java.lang.ref.Reference$Lock) Locked ownable synchronizers: - None "main" prio=10 tid=0xb7606400 nid=0x444 waiting on condition [0xb77f2000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at Test.main(Test.java:5) Locked ownable synchronizers: - None "VM Thread" prio=10 tid=0xb7656800 nid=0x445 runnable "VM Periodic Task Thread" prio=10 tid=0xb7671400 nid=0x44b waiting on condition JNI global references: 125
线程栈各部分介绍
头部信息:
示例:
2016-03-07 18:04:57
Full thread dump Java HotSpot(TM) Client VM (24.80-b11 mixed mode):
内容:
时间,jvm信息
线程info信息块:
示例:
"Finalizer" daemon prio=10 tid=0xb765ac00 nid=0x447 in Object.wait() [0xa14ad000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0xa1a04750> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0xa1a04750> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
Locked ownable synchronizers:
- None
内容:
线程名称:如Finalizer
线程类型:如daemon
优先级: 10,默认是5,如prio=10
jvm线程id:tid=0xb765ac00,jvm内部线程的惟一标识(经过java.lang.Thread.getId()获取,一般用自增方式实现。)
对应系统线程id(Native Thread ID):nid=0x447,和top命令查看的线程pid对应,不过一个是10进制,一个是16进制。(经过命令:top -H -p pid,能够查看该进程的全部线程信息)
线程状态:in Object.wait().
起始栈地址:[0xa14ad000]
线程栈部分:包括线程当前状态和线程栈
线程栈分析工具
IBM Thread and Monitor Dump Analyzer for Java
该工具是一个Jar包,可使用命令启动
java -jar jca457.jar
工做界面以下
JVM中的线程状态
线程在JVM中的各个状态
1.死锁,Deadlock(重点关注)
2.执行中,Runnable(重点关注)
3.等待资源,Waiting on condition(重点关注)
4.等待监控器检查资源,Waiting on monitor(eg:若是使用System.out.println等须要分配计算机资源的时候线程会如此等待,主要还需看堆栈)
5.暂停,Suspended
6.对象等待中,Object.wait()
7.阻塞,Blocked(重点关注)
8.中止,Parked(主要是指线程空闲时候的状态。如在线程池中,当线程被调用后再次放入到池子中,则其状态变为了Parked)
JVM的Thin Lock, Fat Lock, Spin Lock与Tasuki Lock
Java不少ThreadDump中,均可以看到Thin Lock, Fat Lock, Spin Lock,这些Lock都与Java语言、OS有密切的关系。
回到一个简单的问题,在Java中,如何实现Synchronizd?
最简单的一种作法是,利用OS的mutex机制,把Java的同步(基于Object),翻译成OS相关的monitor_enter和monitor_exit原语。
回到Java锁自己,锁在不一样的应用下有着不一样的统计表现,而大部分的统计数据代表,其实线程抢锁,即锁竞争,都是短暂的,在大部分的状况下,几乎都不会发生锁竞争的现象。
也就是说,Java锁,从安全性的角度来看,是有点累赘。
所以,大量的专家都在锁上针对这样的统计特性对Java锁进行优化。
其中一种优化方案是,咱们对全部的锁都须要monitor_enter和monitor_exit吗?事实上不须要。
若是咱们把monitor_enter/monitor_exit当作是Fat Lock方式,则能够把Thin Lock当作是一种基于CAS(Compare and Swap)的简易实现。
这两种锁,简单一点理解,就是:
而基于CAS方式的实现,线程进入竞争状态的,得到锁的线程,会让其余线程处于自旋状态(也称之为Spin Mode,即自旋),这是一种while(Lock_release) doStuff()的Busy-Wait方式,是一种耗CPU的方式;而Fat Lock方式下,一个线程得到锁的时候,其余线程能够先sleep,等锁释放后,再唤醒(Notify)。
CAS的优势是快,若是没有线程竞争的状况下,由于CAS只须要一个指令便得到锁,因此称之为Thin Lock,缺点也是很明显的,即若是频繁发生线程竞争,CAS是低效,主要表现为,排斥在锁以外的线程是Busy Wait状态;而monitor_enter/monitor_exit/monitor_notify方式,则是重量级的,在线程产生竞争的时候,Fat Lock在OS mutex方式下,能够实现no busy-wait。
因而,JVM早期版本的作法是,若是T1, T2,T3,T4...产生线程竞争,则T1经过CAS得到锁(此时是Thin Lock方式),若是T1在CAS期间得到锁,则T2,T3进入SPIN状态直到T1释放锁;而第二个得到锁的线程,好比T2,会将锁升级(Inflation)为Fat Lock,因而,之后尝试得到锁的线程都使用Mutex方式得到锁。
这种设计为锁提供了两条路径:Thin Lock路径和Fat Lock路径,大部分状况下,可能都是走Thin Lock路径,而可能少部分状况,是走Fat Lock路径,这种方式提供了锁升级,可是避免不了Busy Wait,并且Thin-Lock升级Fat-Lock以后,没有办法回退到Thin-Lock(性能比Fat-Lock更好)。
Tasuki锁为这种方式作了2个优化:
1) 避免CAS致使Busy wait
2) Fat Lock能够deflate(与Inflate恰好相反)为Thin Lock(以前是Thin Lock变成Fat Lock以后便不能再回退)。
通过这样的改造后,锁性能提升了10%以上。
目前,Oracle的BEA JRockit与IBM的JVM都实现了Tasuki锁机制,惟一的不一样是,在锁实现上都作了不一样启发式的设计,即根据运行时采样的数据,动态调整一些权值数据,一边左右Lock Inflation/Lock Defaltion的过程(一颗树的两个分支),获取更好的锁性能。
参考文献