public class DeadLock {
public static void main(final String[] args) throws Exception {
final Object lock1 = new Object();
final Object lock2 = new Object();
Thread.currentThread().setName("main-thread");
final Thread r = new Thread("another-thread") {
@Override
public void run() {
try {
synchronized (lock2) {
Thread.sleep(20000);
synchronized (lock1) {
Thread.sleep(20000);
}
}
}
catch (final Exception e) {
e.printStackTrace();
}
}
};
r.start();
Thread.sleep(5000);
synchronized (lock1) {
Thread.sleep(20000);
synchronized (lock2) {
Thread.sleep(20000);
}
}
}
}

这段代码可能有点复杂,但原理不麻烦,就是描述了经典的加锁顺序问题。栈信息比较有趣,裁剪之后如下。

"another-thread" prio= tid=0x02b22400 nid=0x2250 waiting for monitor entry [0x0316f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at DeadLock$.run(DeadLock.java:)
- waiting to lock <0x22bc3f90> (a java.lang.Object)
- locked <0x22bc3f98> (a java.lang.Object) Locked ownable synchronizers:
- None
"main-thread" prio= tid=0x00868800 nid=0x2634 waiting for monitor entry [0x0098f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at DeadLock.main(DeadLock.java:)
- waiting to lock <0x22bc3f98> (a java.lang.Object)
- locked <0x22bc3f90> (a java.lang.Object) Locked ownable synchronizers:
- None
Found one Java-level deadlock:
=============================
"another-thread":
waiting to lock monitor 0x02ad433c (object 0x22bc3f90, a java.lang.Object),
which is held by "main-thread"
"main-thread":
waiting to lock monitor 0x02ad363c (object 0x22bc3f98, a java.lang.Object),
which is held by "another-thread" Java stack information for the threads listed above:
===================================================
"another-thread":
at DeadLock$.run(DeadLock.java:)
- waiting to lock <0x22bc3f90> (a java.lang.Object)
- locked <0x22bc3f98> (a java.lang.Object)
"main-thread":
at DeadLock.main(DeadLock.java:)
- waiting to lock <0x22bc3f98> (a java.lang.Object)
- locked <0x22bc3f90> (a java.lang.Object) Found deadlock.

主线程中提示了当前持有的锁和期望获取的锁,而新线程也存在类似的提示,只是获取锁的顺序不同。从栈信息可以看出,两个线程都处于BLOCKED状态。可能是源代码中的问题过于明显,导出的栈信息中给出了死锁的提示信息,实际项目的业务代码比样例要复杂,JVM可能做不到这么智能。这里的提示信息多多少少有点让我失望,在主线程栈信息的最后一部分没有输出当前持有锁的列表,很奇怪,不知道是不是和JDK的实现有关。

import java.security.SecureRandom;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock; public class DeadLock {
private final ReentrantLock lock = new ReentrantLock();
private static final SecureRandom random = new SecureRandom(); public DeadLock() {
} public void runWork() { final ThreadPoolExecutor threadpool = new ThreadPoolExecutor(3, 3, 60L, TimeUnit.DAYS,
new SynchronousQueue<Runnable>(), new ThreadFactory() {
private final AtomicInteger counter = new AtomicInteger(1);
@Override
public Thread newThread(final Runnable r) {
return new Thread(r, "thread-sn-" + counter.getAndIncrement());
}
});
threadpool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
Thread.currentThread().setName("main-thread");
for (int i = 0; i < 15; ++i) {
threadpool.submit(new Runnable() {
@Override
public void run() {
try { int timeout = 0;
while ((timeout = random.nextInt()) <= 0) {
}
timeout = timeout % 111;
Thread.sleep(timeout * 100L); lock.lock();
callLongTime(); }
catch (final Exception e) {
e.printStackTrace();
}
finally {
lock.unlock();
}
}
});
}
threadpool.shutdown();
} public static void main(final String[] args) throws Exception {
new DeadLock().runWork();
} static long callLongTime() {
System.out.println("thread name " + Thread.currentThread().getName());
long sum = 0;
for (long i = 0; i < 10000000000L; ++i) {
sum = sum ^ i + i;
}
return sum;
}
}

最后一个样例,写的比较复杂,但事情比较简单,线程之间的同步关键字换成了Java5提供的concurrent库中的重入锁。

"thread-sn-3" prio= tid=0x02de8400 nid=0x2688 runnable [0x0320f000]
java.lang.Thread.State: RUNNABLE
at DeadLock.callLongTime(DeadLock.java:)
at DeadLock$.run(DeadLock.java:)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:)
at java.util.concurrent.FutureTask.run(FutureTask.java:)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:)
at java.lang.Thread.run(Thread.java:) Locked ownable synchronizers:
- <0x22be1488> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
- <0x22be66d8> (a java.util.concurrent.ThreadPoolExecutor$Worker) "thread-sn-2" prio= tid=0x02de6c00 nid=0x218c waiting on condition [0x031bf000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x22be1488> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:)
at DeadLock$.run(DeadLock.java:)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:)
at java.util.concurrent.FutureTask.run(FutureTask.java:)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:)
at java.lang.Thread.run(Thread.java:) Locked ownable synchronizers:
- <0x22be64e0> (a java.util.concurrent.ThreadPoolExecutor$Worker)

栈信息比较有趣,JVM在每个线程线的最后部分输出了当前线程持有的锁对象,类型和地址。从上述的信息中可以找到,当前处于运行状态的线程持有了一个地址为0x22be1488的锁,而这个锁正是其它线程等待获取的锁对象。

http://blog.csdn.net/jackie_xiaonan/article/details/8577785

Locked ownable synchronizers(转)的更多相关文章

  1. 检查死锁与Locked ownable synchronizers(转载)

    通过jstack可快速检查线程的死锁信息,用法如下: # 获取JVM ID(JAVA 进程ID),通过参数lv可以获取更详细的JAVA方法调用信息 jps -lv # 得到JVM ID后,执行jsta ...

  2. 《深入理解Java虚拟机》虚拟机性能监控与故障处理工具

    上节学习回顾 从课本章节划分,<垃圾收集器>和<内存分配策略>这两篇随笔同属一章节,主要是从理论+实验的手段来讲解JVM的内存处理机制.好让我们对JVM运行机制有一个良好的概念 ...

  3. jvm系列(四):jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)

    文章同步发布于github博客地址,阅读效果更佳,欢迎品尝 运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎 ...

  4. Java线程问题分析定位

    Java线程问题分析定位 分析步骤: 1.使用top命令查看系统资源占用情况,发现Java进程占用大量CPU资源,PID为11572: 2.显示进程详细列表命令:ps -mp 11572 -o THR ...

  5. 一则JVM memory leak解决的过程

    起因是我们的集群应用(3台机器)新版本测试过程中,一般的JVM内存占用 都在1G左右, 但在运行了一段时间后,慢慢升到了4G, 这是一个明显不正常的现象. 定位 过程: 1.先在该机器上按照步骤尝试重 ...

  6. Java多线程之Runable与Thread

    Java多线程是Java开发中的基础内容,但是涉及到高并发就有很深的研究可做了. 最近看了下<Java并发实战>,发先有些地方,虽然可以理解,但是自己在应用中很难下手. 所以还是先回顾一下 ...

  7. 不正确使用WeakHashMap引起的卡死

    公司的jenkins今天出了一点问题,起来以后,总是处于等待状态,所有的任务无法正常加载.登陆界面也出不了.而且cpu占用率100% 把线程导出来,看到: “Loading job NMS_Patch ...

  8. [已解决] java.net.InetAddress.getHostName() 阻塞问题

    在学习java nio的过程中发现某些情况下使用该方法会导致程序阻塞,(情况:服务器,Linux:客户端,WIN10) java.net.InetAddress.getHostName() 阻塞情况如 ...

  9. 怎样分析java线程堆栈日志

    注: 该文章的原文是由 Tae Jin Gu 编写,原文地址为 How to Analyze Java Thread Dumps 当有障碍,或者是一个基于 JAVA 的 WEB 应用运行的比预期慢的时 ...

随机推荐

  1. 用yum查询想安装的软件

    1.使用YUM查找软件包  命令:yum search~  2.列出所有可安装的软件包  命令:yum list  3.列出所有可更新的软件包  命令:yum list updates  4.列出所有 ...

  2. 关于iptables的u32匹配

    前面一篇文章----阐释了iptables最新的bpf match,说它将多个matches并成了一个经过编译的解释型bytecode bpf match,早在bpf match之前,u32 matc ...

  3. Delphi读写UTF-8、Unicode格式文本文件

    // UTF-8文件写入函数procedure SaveUTFFile(const FileName: string; S: string; WriteHeader: Boolean = True); ...

  4. 与众不同 windows phone (20) - Device(设备)之位置服务(GPS 定位), FM 收音机, 麦克风, 震动器

    原文:与众不同 windows phone (20) - Device(设备)之位置服务(GPS 定位), FM 收音机, 麦克风, 震动器 [索引页][源码下载] 与众不同 windows phon ...

  5. Lisp的永恒之道 好文

    http://www.cnblogs.com/weidagang2046/archive/2012/06/03/tao_of_lisp.html

  6. osgEarth开发之OSG解构——失败的尝试

    概述 本文在吸收了<最长的一帧>以及相关参考资料的基础之上解读OSG的基础数据结构,渲染方法. 实现 在这第一部分里,要理解的是run函数的实现,因为以下这一段证明了它的重要性和强大的能力 ...

  7. 解决xShell4某些情况下按删除键会输出^H的问题

    当我们用Xshell登录进入linux后,在普通模式下,对输入进行删除等操作没有问题. 而在执行中,按delete,backspace键时会产生^H等乱码问题. 这是由于编码不匹配的问题. 解决方法: ...

  8. Android在onInterceptTouchEvent与onTouchEvent

    onInterceptTouchEvent: onInterceptTouchEvent是在ViewGroup里面定义的.Android中的layout布局类一般都是继承此类的.onIntercept ...

  9. 最终结算“Git Windowsclient保存username与password”问题

    Git - How to use netrc file on windows - Stack Overflow 这就是正确答案,我们已经验证过了,以下具体描写叙述一下解决方法: 1. 在Windows ...

  10. 属性“dataProvider”有多个初始值设定项。(注意:“dataProvider”是“mx.charts.BarChart”的默认属性)。

    1.错误描写叙述 属性"dataProvider"有多个初始值设定项.(注意:"dataProvider"是"mx.charts.BarChart&q ...