当前位置 博文首页 > dfug3303的博客:什么是死锁以及避免死锁

    dfug3303的博客:什么是死锁以及避免死锁

    作者:[db:作者] 时间:2021-07-31 12:25

    一、定义

      线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。

    当然死锁的产生是必须要满足一些特定条件的:?
    1.互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放?
    2.请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。?
    3.不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用?
    4.循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。

    package com.sxy.thread;

    /**
    * 线程Thread1率先占有了resource1, 继续运行时需要resource2, 但此时resource2却被线程Thread2占有了,
    * 因此只能等待Thread2释放resource2才能够继续运行; 同时,Thread2也需要resource1,
    * 它只能等待Thread1释放resource1才能够继续运行, 因此,Thread1和Thread2都处于等待状态,
    * 谁也无法继续运行,即产生了死锁。
    *
    * @author sunxy
    */
    public class DeadLock {

    public static void main(String[] args) {
    dead_lock();
    }

    private static void dead_lock() {
    // 两个资源
    final Object resource1 = "resource1";
    final Object resource2 = "resource2";
    // 第一个线程,想先占有resource1,再尝试着占有resource2
    Thread t1 = new Thread() {
    public void run() {
    // 尝试占有resource1
    synchronized (resource1) {
    // 成功占有resource1
    System.out.println("Thread1 1:locked resource1");
    // 休眠一段时间
    try {
    Thread.sleep(50);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    // 尝试占有resource2,如果不能占有,该线程会一直等到
    synchronized (resource2) {
    System.out.println("Thread1 1:locked resource2");
    }
    }
    }
    };
    // 第二个线程,想先占有resource2,再占有resource1
    Thread t2 = new Thread() {
    public void run() {
    // 尝试占有resource2
    synchronized (resource2) {
    // 成功占有resource2
    System.out.println("Thread 2 :locked resource2");
    // 休眠一段时间
    try {
    Thread.sleep(50);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    // 尝试占有resource1,如果不能占有,该线程会一直等到
    synchronized (resource1) {
    System.out.println("Thread1 2:locked resource1");
    }
    }
    }
    };
    // 启动线程
    t1.start();
    t2.start();
    }
    }

    死锁的另一种:递归死锁,举例:

    所谓递归函数就是自调用函数,在函数体内直接或间接的调用自己,即函数的嵌套是函数本身。?
    递归方式有两种:直接递归和间接递归,直接递归就是在函数中出现调用函数本身。间接递归,指函数中调用了其他函数,而该其他函数又调用了本函数。
    那什么时候使用递归呢?一般来说当你要在某段代码逻辑中使用循环迭代的时候但是迭代的次数在迭代之前无法知晓的情况下使用递归。打个比方你要在一个文件夹中查找某个文件,而这个文件夹底下有N多子文件夹和文件,当你在不知道有多少层文件夹和文件的情况下你就得用到递归了。
    递归的优点就是让代码显得很简洁,同时有些应用场景不得不使用递归比如前面说的找文件。递归是个好东西但是在某些时候也会给你带来一些麻烦。比如在多线程的环境下使用递归,遇到了多线程那么就不得不面对同步的问题。而递归程序遇到同步的时候很容易出问题。多线程的递归就是指递归链中的某个方法由另外一个线程来操作,以下代码的意思都是这个意思即调用recursive()和businessLogic()并非一个线程(如果是在一个线程中就不存在死锁问题,例如下面的recursive变成private就不存在问题。)

    ?

    [java]? view plain ?copycs
    下一篇:没有了