线程死锁
2016-01-03 21:01
357 查看
何为死锁
两个线程相互等待对方已锁定的资源,产生死锁如何避免死锁
其实这个问题很难回答,因为至少目前在Java领域,在语言层面是无法避免死锁的。更多的是依赖编程经验。模拟死锁
比如有两个线程,共享一个对象。该对象持有 A、B 两份资源。线程1负责读取,线程2负责写入。读取线程先占用A的锁,然后准备获取B的锁;写入线程先占用B的锁,再获取A的锁。
这个过程非常简单,但是一旦进入某个临界点,即读取线程等待写入线程占有的B锁。
写入线程等待读取线程占有的A锁,那么就很容易就产生了死锁。看如下代码演示。
/** * DeadLockDemo.java * com.yli.thread.demo */ package com.yli.thread.demo; /** * 死锁模拟 * * @author yli * @since Ver 1.1 * @Date 2016 2016年1月3日 下午8:29:01 */ public class DeadLockDemo { public static void main(String[] args) { // 共享对象 DeadLock deadObj = new DeadLock(); // 读取线程 DeadLockRead threadRead = new DeadLockRead(deadObj); // 写入线程 DeadLockWrite threadWrite = new DeadLockWrite(deadObj); // 启动读取线程 threadRead.start(); // 启动写入线程 threadWrite.start(); } // 读取线程class private static class DeadLockRead extends Thread { private DeadLock dead; public DeadLockRead(DeadLock deadObj) { dead = deadObj; } @Override public void run() { dead.read(); } } // 写入线程class private static class DeadLockWrite extends Thread { private DeadLock dead; public DeadLockWrite(DeadLock deadObj) { dead = deadObj; } @Override public void run() { dead.write(); } } } // 共享对象提供read和write方法 class DeadLock { private Object objA = new Object(); private Object objB = new Object(); public void read() { String currentThread = Thread.currentThread().getName(); // 先让读取线程获取objA的锁 synchronized (objA) { System.out.println(currentThread + " 获得了Obj-A的锁"); try { System.out.println(currentThread + " 休眠10s,让其他线程先获得Obj-B的锁!"); Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } // 视图获得obj-B对象的锁,但write线程已经获得该对象的锁! synchronized (objB) { System.out.println(currentThread + " 获得了Obj-B的锁"); } } } public void write() { String currentThread = Thread.currentThread().getName(); try { // 写入线程先休眠300毫米,确保读取线程已经运行起来,且获得objA的锁 Thread.sleep(300); } catch (InterruptedException e1) { e1.printStackTrace(); } // 由于读取线程获得objA的锁之后,会休眠10秒,所以写入线程有充分时间先获得objB的锁 synchronized (objB) { System.out.println(currentThread + " 获得了Obj-B的锁"); // 视图获得obj-A的锁,但read线程已经获得该对象上的锁 synchronized (objA) { System.out.println(currentThread + " 获得了Obj-A的锁"); } } } }
检测死锁
之前介绍,在语言层面是无法阻止产生死锁的,但还好有工具为我们检测死锁提供便利,介绍两种常见方法。方法1 jconsole 检测死锁
使用JDK bin目录下的jconsole工具,先运行上述demo,再打开该工具方法2 jstack 检测死锁
jconsole提供可视化窗体来检测死锁,也是JDK官方提供的非常强大的JVM故障定位工具。但对于很多运行在linux上的应用来说,如果在未授权的情况下,通过运行在windows上的jconsole来远程连接运行在linux的JVM,可能不是很方便,特别是在很多大公司,特别是线上环境!!!你几乎没有任何机会来使用这种工具,主要是担心我们不专业,把线上直接搞崩溃。。。
所以,jstack 命令行工具就可以派上用场了,它也是JDK bin目录下的一个工具,非常强大
如果在windows环境,cmd进入命令行窗口
step1-获取JVM进程号
如果你在linux上运行Java应用程序,也可以直接使用jsp命令,如果不允许使用该命令,那么这样
ps -ef|grep java 获取所有JVM的进程号,找到你想要的即可
step2-打印当前JVM堆栈
如果在linux上,也可以直接运行该命令,如果不允许使用。。。那就没辙了,找相应管理员给你授权。
step3-发现死锁信息
在step2结束之后,你就拿到JVM当前堆栈信息了,在使用 jstack 命令时,因为带上了 -l 选项,所以会打印出死锁信息,如下所示。
如果对JVM常用工具不熟悉,可以参考:http://blog.csdn.net/lojze_ly/article/details/49498981
相关文章推荐
- 死锁
- java死锁问题定位
- java多线程-java死锁
- JAVA最直观的死锁代码
- 多线程死锁的一个简单例子
- Java 死锁
- java死锁
- Java多线程死锁的产生原因以及如何避免
- 【Java EE 学习 82 下】【MAVEN整合Eclipse】【MAVEN的一些高级概念】
- 初学java感想
- Java Nio 五、分散/聚集
- Struts2和hibernate3的简单应用-登录验证
- Myeclipse 10.7 android(安卓) 开发环境搭建
- java配置环境变量
- 【jersey】 spring 整合jersey 实现RESTful webservice
- MyEclipse代码不能自动补全的解决办法
- Java关键字(四)static关键字(静态代码块)
- struts2学习
- springMVC的Restful接口实现
- 【Android Studio使用教程5】使用SDK Manager时, SDK下载更新不了的解决方案(eclipse 也适用)