死锁

在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

原文地址:https://www.cnblogs.com/sun-rain/p/5731389.html