[JAVAee]死锁

目录

死锁产生的条件

死锁的避免


多线程的环境下,我们会给线程进行加锁.在某种特定的情况下,可能会产生无限的循环等待.由于上锁不当导致的这种多个线程堵塞循环等待,可以称其为"死锁".

死锁产生的条件

死锁产生有四个必要的条件,只有同时满足才会出现死锁

  1. 互斥使用:一个资源只能被一个线程所占用
  2. 不可抢占:当资源被线程占用时,其他线程不能强制抢占当前被使用中的资源
  3. 请求和保持:占用着资源的线程申请占用其他资源(吃着碗里的,看着锅里的)
  4. 循环等待:A占用B申请的资源,B占用C申请的资源,C占用A申请的资源

对于条件1与2,使用了synchronized关键字进行上锁后就会产生的特性.

条件3与4是代码逻辑上可能会产生的问题. 

        Object lock1 = new Object();
        Object lock2 = new Object();

        Thread thread0 = new Thread(() -> {
            synchronized (lock1){
                synchronized (lock2){
                    //
                }
            }
        });
        thread0.start();
        Thread thread1 = new Thread(() -> {
           synchronized (lock2){
               synchronized (lock1){
                   //
               }
           }
        });
        thread1.start();

以上的这段代码,就有可能会产生循环等待导致死锁.

线程0首先被调度,对lock1进行占用.再到线程1被调度,对lock2进行占用.

再到线程0想要对lock2申请资源的时候,发现lock2已经被线程1占用了.

与此同时,线程1想要对lock1申请资源,发现lock1已经被线程0占用了,这时候两个线程就产生了阻塞导致了无限的等待循环.

死锁的避免

想要打破死锁,只要任意的打破四个条件中的一个就可以满足

最常用的技术是,锁排序.

假设有N个线程尝试获取M把锁的时候.就可以将锁进行排序(0,1,2,3......M).

并且线程都分别按照一定的顺序获取锁,就可以避免循环等待.

像下面的代码,锁的获取有着一定的顺序,就可以避免死锁的产生

        Object lock1 = new Object();
        Object lock2 = new Object();

        Thread thread0 = new Thread(() -> {
            synchronized (lock1){
                synchronized (lock2){
                    //
                }
            }
        });
        thread0.start();
        Thread thread1 = new Thread(() -> {
           synchronized (lock1){
               synchronized (lock2){
                   //
               }
           }
        });
        thread1.start();

你可能感兴趣的:(java,开发语言)