死锁
在Java开发应用中,锁时一直非常有用的工具,使用也很简单。但是它可能会引起死锁,造成系统功能不能使用。
看一段代码:
public class Deadlock { public static void main(String[] args) { deadlock(); } private static String A = "A"; private static String B = "B"; static void deadlock(){ Thread t1 = new Thread(new Runnable() { @Override public void run() { //获取当前线程的名称 System.out.println(Thread.currentThread().getName()); synchronized(A){ System.out.println("t1-->synchronized(A)"); try { //睡眠 时间设置 不加的话可能会死锁,也可能会顺利执行完 //为保证死锁状态 必须加上 //Thread.sleep(1000); synchronized(B){ System.out.println("t1--->synchronized(B)"); } } catch (Exception e) { e.printStackTrace(); } }; } },"线程1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { //获取当前线程的名称 System.out.println(Thread.currentThread().getName()); synchronized(B){ System.out.println("t2--->synchronized(B)"); synchronized(A){ System.out.println("t2--->synchronized(A)"); } }; } },"线程2"); t1.start(); t2.start(); //获取当前线程的名称 System.out.println(Thread.currentThread().getName()); } }
这段代码是演示死锁的场景,实际开发中,我们可能不会写这样的代码。可是,在一些复杂的业务中,
可能会会发生,t1拿到锁后因为某些异常导致锁不会释放掉,死循环状态,或者t1拿到数据库的锁,
释放锁的时候抛出异常,释放失败。
解决思路:通过dump线程查看后台到底哪个线程出现问题及其异常信息。
避免死锁的常见方法:
1.避免一个线程同时获取多个锁。
2.避免一个线程同时占用多个资源,尽量保证每把锁只占用一个资源。
3.尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
4.对于数据库锁,加锁和解锁必须在同一个数据库连接中,否则会出现解锁失败的情况。
dump:
dump 文件里,值得关注的线程状态有:
死锁,Deadlock(重点关注)
执行中,Runnable
等待资源,Waiting on condition(重点关注)
等待获取监视器,Waiting on monitor entry(重点关注)
暂停,Suspended
对象等待中,Object.wait() 或 TIMED_WAITING
阻塞,Blocked(重点关注)
停止,Parked
http://www.cnblogs.com/nexiyi/p/java_thread_jstack.html
定时锁:
Lock接口是Java 5.0新增的接口,
与内置加锁机制不同的是,Lock提供了一种无条件的、可轮询的、定时的以及可中断的锁获取操作,
所有加锁和解锁的方法都是显示的。ReentrantLock实现了Lock接口,与内置锁相比,
ReentrantLock有以下优势:可以中断获取锁操作,获取锁时候可以设置超时时间。
http://www.hello-code.com/blog/java/201412/4849.html
IT技术和行业交流群 417691667