死锁详解

死锁实现

public class DeathLockTest {

    static Integer b = 100;
    static Integer a = 0;
    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (a){
                System.out.println(Thread.currentThread().getName() + ": i locked a");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (b){
                    System.out.println(Thread.currentThread().getName() + ": i locked b");
                }
            }
        },"thread-a").start();
        new Thread(() -> {
            synchronized (b){
                System.out.println(Thread.currentThread().getName() + ": i locked b");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (a){
                    System.out.println(Thread.currentThread().getName() + ": i locked a");
                }
            }
        },"thread-b").start();
    }
}
死锁结果

这里简单的用了两个线程去分别获取到a的锁和b的锁,然后再获取另外一个锁的时候,就发现互相等待,互相不会释放资源,导致死锁的发生。死锁在我们的项目中会导致很严重的后果,有多严重,碰到的人知道。

定义

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。[百度百科]

如何避免

1:获取锁的顺序问题
如果我们在获取两个资源的时候,获取的顺序相同,都先获取到a的锁,然后再获取到b的锁,则在上述例子中避免了死锁。
2:避免同时持有两个资源的锁
假设上面的例子中,thread-a获取到a的锁以后,对a的操作进行完成以后再获取b的锁,那么,就可以解开这个死锁,thread-b同理。
3:使用java.util.concurrent包中的相关方法改造
对上面的代码进行改造

public class DeathLockTest2 {
    
    static Integer a = 0;
    static Integer b = 100;

    static Lock lock1 = new ReentrantLock();
    static Lock lock2 = new ReentrantLock();

    public static void main(String[] args) {
        new Thread(()->{
            try{
                if(lock1.tryLock()){
                    System.out.println(Thread.currentThread().getName() + ": lock1 was locked");
                    a++;
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(lock2.tryLock()){
                        System.out.println(Thread.currentThread().getName()+ " lock2 was locked");
                        b--;
                    }
                    System.out.println(Thread.currentThread().getName()+ "--> ++a :" + a + " ,  --b:" + b);
                }
            }finally {
                    lock1.unlock();
                    lock2.unlock();
            }
        },"thread-a").start();
        new Thread(()->{
            try {
                if(lock2.tryLock()){
                    System.out.println(Thread.currentThread().getName()+ " lock2 was locked");
                    b--;
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(lock1.tryLock()){
                        System.out.println(Thread.currentThread().getName() + ": lock1 was locked");
                        a++;
                    }
                }
                System.out.println(Thread.currentThread().getName()+ "--> ++a :" + a + " ,  --b:" + b);
            }finally {
                lock2.unlock();
                lock1.unlock();
            }
        },"thread-b").start();
        //定时器计时
        new Timer().schedule(new TimerTask(){
            @Override
            public void run() {
                System.out.println(String.valueOf(Calendar.getInstance().get(Calendar.SECOND)));
            }
        }, 1, 1000);
    }
}

使用java.util.concurrent.locks.Lock.tryLock()方法,结果如下:

解锁

程序在等待了5s左右的时候,线程自动结束运行了,使用这种方式则不会使我们的线程出现完全死锁,程序无法进行的状态,在等待一定时间后,线程无法获取到锁,则自动放弃获取锁。

结束语:可能还有更好的解决办法,欢迎大家留言指正探讨,谢谢!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容