Java中的线程是内核线程和用户线程一起实现的,状态图(参见java.lang.Thread,实际上只有6个状态,为了更好理解线程状态,图中添加了不存在的状态Running)如下:
很多时候,我们系统出现:线程阻塞、死锁、不能创建更多本地线程的OOME、CPU消耗过多等等;甚至有些堆内存溢出也可能跟线程有关,因为可能是创建了过多的线程导致堆内存不够用。问题排查需要深入到线程的dump信息中:
常见问题排查工具:jstack命令 或者 JvisualVM或其他第三方工具
为了更好地分析线程dump信息,举个栗子:5线程交替打印123456789...100000,程序如下:
package com.ali.review;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
/**
* Created by lucene on 2017/6/14.
*/
public class PrintDataThread implements Runnable {
private int max;
private AtomicInteger counter;
private int mod;
private int remainder;
Condition condition;
public PrintDataThread(int max, AtomicInteger counter, int mod, int remainder) {
this.max = max;
this.counter = counter;
this.mod = mod;
this.remainder = remainder;
}
public void run() {
while (counter.get() < max) {
synchronized (counter) {
if ((counter.get() % mod) == remainder && counter.get() < max) {
int currentNum = counter.addAndGet(1);
System.out.println("Thread " + Thread.currentThread().getId() + "-----" + currentNum);
counter.notifyAll();
}else{
try {
counter.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
package com.ali.review;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by lucene on 2017/6/14.
*/
public class PrintDataMain {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(5);
AtomicInteger counter = new AtomicInteger(0);
int max = 100000;
int mod = 5;
long before = System.currentTimeMillis();
for (int i = 0; i < mod; i++) {
threadPool.execute(new PrintDataThread(max, counter, mod, i));
}
threadPool.shutdown();
while (!threadPool.isTerminated()) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(System.currentTimeMillis() - before);
}
}
运行结果:
。。。
Thread 10-----99981
Thread 11-----99982
Thread 12-----99983
Thread 13-----99984
Thread 14-----99985
Thread 10-----99986
Thread 11-----99987
Thread 12-----99988
Thread 13-----99989
Thread 14-----99990
Thread 10-----99991
Thread 11-----99992
Thread 12-----99993
Thread 13-----99994
Thread 14-----99995
Thread 10-----99996
Thread 11-----99997
Thread 12-----99998
Thread 13-----99999
Thread 14-----100000
线程dump信息
2017-06-18 00:15:44
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.75-b04 mixed mode):
"RMI TCP Connection(2)-192.168.0.100" daemon prio=6 tid=0x000000000ac7f000 nid=0x1110 runnable [0x000000000c7ad000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
- locked <0x00000000c15780d0> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:549)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.access$400(TCPTransport.java:619)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(TCPTransport.java:684)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(TCPTransport.java:681)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:681)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00000000c1536d98> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"JMX server connection timeout 19" daemon prio=6 tid=0x000000000aceb800 nid=0x1c24 in Object.wait() [0x000000000c4ae000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
- locked <0x00000000c15328b8> (a [I)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"RMI Scheduler(0)" daemon prio=6 tid=0x000000000acec800 nid=0x88c waiting on condition [0x000000000c3ae000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c1498070> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2082)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1090)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"RMI TCP Connection(1)-192.168.0.100" daemon prio=6 tid=0x000000000aceb000 nid=0xf84 runnable [0x000000000c2ae000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
- locked <0x00000000c1494348> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:549)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.access$400(TCPTransport.java:619)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(TCPTransport.java:684)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(TCPTransport.java:681)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:681)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00000000c1494508> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"RMI TCP Accept-0" daemon prio=6 tid=0x000000000ad06800 nid=0x2780 runnable [0x000000000c0af000]
java.lang.Thread.State: RUNNABLE
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
- locked <0x00000000c14922c8> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:530)
at java.net.ServerSocket.accept(ServerSocket.java:498)
at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:52)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:399)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:371)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"pool-1-thread-5" prio=6 tid=0x000000000aa6c800 nid=0x26e8 in Object.wait() [0x000000000b3af000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at com.ali.review.PrintDataThread.run(PrintDataThread.java:33)
- locked <0x00000000c142c0f0> (a java.util.concurrent.atomic.AtomicInteger)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00000000c14236a8> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"pool-1-thread-4" prio=6 tid=0x000000000aa69800 nid=0x1240 in Object.wait() [0x000000000b2af000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at com.ali.review.PrintDataThread.run(PrintDataThread.java:33)
- locked <0x00000000c142c0f0> (a java.util.concurrent.atomic.AtomicInteger)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00000000c14237d8> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"pool-1-thread-3" prio=6 tid=0x000000000aa13000 nid=0x2008 waiting for monitor entry [0x000000000b1af000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at com.ali.review.PrintDataThread.run(PrintDataThread.java:33)
- locked <0x00000000c142c0f0> (a java.util.concurrent.atomic.AtomicInteger)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00000000c1423578> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"pool-1-thread-2" prio=6 tid=0x000000000aa12000 nid=0xfe0 in Object.wait() [0x000000000b0ae000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at com.ali.review.PrintDataThread.run(PrintDataThread.java:33)
- locked <0x00000000c142c0f0> (a java.util.concurrent.atomic.AtomicInteger)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00000000c1423448> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"pool-1-thread-1" prio=6 tid=0x000000000a98c800 nid=0x1b50 in Object.wait() [0x000000000afaf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at com.ali.review.PrintDataThread.run(PrintDataThread.java:33)
- locked <0x00000000c142c0f0> (a java.util.concurrent.atomic.AtomicInteger)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00000000c1423318> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"Monitor Ctrl-Break" daemon prio=6 tid=0x000000000a997000 nid=0xcc0 runnable [0x000000000ae3e000]
java.lang.Thread.State: RUNNABLE
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
- locked <0x00000000c1423a68> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:530)
at java.net.ServerSocket.accept(ServerSocket.java:498)
at com.intellij.rt.execution.application.AppMain$1.run(AppMain.java:90)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"Service Thread" daemon prio=6 tid=0x0000000008fb7000 nid=0x1f40 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread1" daemon prio=10 tid=0x0000000008fb1000 nid=0x348 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread0" daemon prio=10 tid=0x0000000008faf000 nid=0x2108 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Attach Listener" daemon prio=10 tid=0x0000000008fae800 nid=0x2350 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Signal Dispatcher" daemon prio=10 tid=0x0000000008fab800 nid=0x2234 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Finalizer" daemon prio=8 tid=0x0000000008f5f800 nid=0xfac in Object.wait() [0x000000000a30f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x00000000c1408f20> (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=0x0000000008f56800 nid=0x1d14 in Object.wait() [0x000000000a20e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
- locked <0x00000000c1408920> (a java.lang.ref.Reference$Lock)
Locked ownable synchronizers:
- None
"main" prio=6 tid=0x00000000030d0800 nid=0x2578 waiting on condition [0x00000000030ce000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.ali.review.PrintDataMain.main(PrintDataMain.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Locked ownable synchronizers:
- None
"VM Thread" prio=10 tid=0x0000000008f52800 nid=0x11c4 runnable
"GC task thread#0 (ParallelGC)" prio=6 tid=0x00000000030e7800 nid=0x2374 runnable
"GC task thread#1 (ParallelGC)" prio=6 tid=0x00000000030e9000 nid=0x1980 runnable
"GC task thread#2 (ParallelGC)" prio=6 tid=0x00000000030eb000 nid=0x242c runnable
"GC task thread#3 (ParallelGC)" prio=6 tid=0x00000000030ec800 nid=0xd04 runnable
"VM Periodic Task Thread" prio=10 tid=0x0000000008fda000 nid=0x2774 waiting on condition
JNI global references: 165
线程dump信息中可以看到:RUNNABLE、TIMED_WAITING (on object monitor)、BLOCKED、WAITING (线程创建和终止状态不在dump中体现)
对dump信息我们尤其要注意:
死锁,Deadlock(重点关注)
执行中,Runnable
等待资源,Waiting on condition(重点关注)
等待获取监视器,Waiting on monitor entry(重点关注)
"pool-1-thread-3" prio=6 tid=0x000000000aa13000 nid=0x2008 waiting for monitor entry [0x000000000b1af000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at com.ali.review.PrintDataThread.run(PrintDataThread.java:33)
- locked <0x00000000c142c0f0> (a java.util.concurrent.atomic.AtomicInteger)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)Locked ownable synchronizers:
- <0x00000000c1423578> (a java.util.concurrent.ThreadPoolExecutor$Worker)
进入waiting for monitor entry的原因是使用了 counter.wait()
暂停,Suspended
对象等待中,Object.wait() 或 TIMED_WAITING
阻塞,Blocked(重点关注)
停止,Parked