纵有疾风起
人生不言弃

死锁详解

死锁实现

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()方法,结果如下:

死锁详解插图1
解锁

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

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

文章转载于:https://www.jianshu.com/p/07a43e0fba26

原著是一个有趣的人,若有侵权,请通知删除

未经允许不得转载:起风网 » 死锁详解
分享到: 生成海报

评论 抢沙发

评论前必须登录!

立即登录