vmstat 可以查看上下文切换的次数 http://www.cnblogs.com/ggjucheng/archive/2012/01/05/2312625.html
root@ubuntu:~# vmstat 2 1
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
1 0 0 3498472 315836 3819540 0 0 0 1 2 0 0 0 100 0
jstack PID > /tmp/dump17 查看PID中线程的状态
2017-11-10 17:39:05
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.45-b02 mixed mode):
"Attach Listener" #3381 daemon prio=9 os_prio=0 tid=0x00007f3c08075800 nid=0x1e58 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Worker-408" #3380 prio=5 os_prio=0 tid=0x0000000001bd7000 nid=0x8ea in Object.wait() [0x00007f3bc43f7000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)
- locked <0x00000000c149edb0> (a org.eclipse.core.internal.jobs.WorkerPool)
at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:52)
grep java.lang.Thread.State /tmp/dump17 | awk '{print $2$3$4$5}' | sort | uniq -c
11 RUNNABLE
12 TIMED_WAITING(onobjectmonitor)
1 TIMED_WAITING(parking)
2 TIMED_WAITING(sleeping)
29 WAITING(onobjectmonitor)
20 WAITING(parking)
sort 按照ASCII码排序, sort -n 按照数字排序, sort -r 倒序排序
uniq 去除重复行, uniq -d 只显示重复行, uniq -u只显示出现一次的行 uniq -c prefix lines by the number of occurrences
执行 uniq --help可查看使用情况
这里记录一下线程的几种状态
死锁,Deadlock(重点关注)
执行中,Runnable
等待资源,Waiting on condition(重点关注)
等待获取监视器,Waiting on monitor entry(重点关注)(entry set)
暂停,Suspended
对象等待中,Object.wait() 或 TIMED_WAITING (wait set)
阻塞,Blocked(重点关注)
停止,Parked
参考文章 http://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html
实例分析一段代码,找到死锁的根源
public class DeadLock {
private static String A = "A";
private static String B = "B";
public static void main(String[] args) {
new DeadLock().deadLock();
}
private void deadLock() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (A) {
System.out.println("[Thread1] Got A");
synchronized (B) { //blocked
System.out.println("[Thread1] Got B");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("The thread is interruped " + e.getMessage());
}
}
}
}
});
Thread t2 = new Thread() {
public void run() {
synchronized(B){
System.out.println("[Thread2] Got B");
synchronized(A){ // blocked
System.out.println("[Thread2] Got A");
try{
Thread.sleep(1000);
}
catch(InterruptedException e) {
System.out.println("The thread is interruped " + e.getMessage());
}
}
}
}
};
t1.start();
t2.start();
}
}
我们执行下列命令
ps -aux | grep DeadLock 可以获得进程PID
jstack 31165 > /tmp/dump31165
vi /tmp/dump3116
"Thread-1" #9 prio=5 os_prio=0 tid=0x00007f093c0d2800 nid=0x79d2 waiting for monitor entry [0x00007f0925783000]
java.lang.Thread.State: BLOCKED (on object monitor)
at JavaConcurrency.Test.DeadLock$2.run(DeadLock.java:37)
- waiting to lock <0x0000000782b5aba8> (a java.lang.String)
- locked <0x0000000782b5abd8> (a java.lang.String)
"Thread-0" #8 prio=5 os_prio=0 tid=0x00007f093c0d1000 nid=0x79d1 waiting for monitor entry [0x00007f0925884000]
java.lang.Thread.State: BLOCKED (on object monitor)
at JavaConcurrency.Test.DeadLock$1.run(DeadLock.java:19)
- waiting to lock <0x0000000782b5abd8> (a java.lang.String)
- locked <0x0000000782b5aba8> (a java.lang.String)
at java.lang.Thread.run(Thread.java:745)
可以看到这两个线程互相等待对方的锁, 可见 jstack 是根据线程状态来分析死锁是很有用的,虽然上面的代码非常简单,但是在复杂的业务场景中,这是个浓缩版的死锁
避免死锁的方式:
避免一个线程同时获取多个锁
避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制(在以后的文章中需要详细了解下定时锁)
对于数据库锁,加锁和解锁必须在同一个数据库连接里,否则会出现解锁失败的情况 (后续需要看一下数据库的内容)