首页 \ 问答 \ 使用ReentrantLock避免死锁(Avoiding deadlock using ReentrantLock)

使用ReentrantLock避免死锁(Avoiding deadlock using ReentrantLock)

我正在做一些练习作业,并涉及一些虚拟代码,试图更好地理解线程和锁的概念。 以下是一段代码(有时)陷入僵局。

A.java

public class A {

    private B b;

    public void setB(B b) {
        this.b = b;
    }

    public synchronized void foo(boolean callBar) {
        System.out.println("foo");
        if (callBar) {
            b.bar(false);
        }
    }
}

B.java

public class B {

    private A a;

    public void setA(A a) {
        this.a = a;
    }

    public synchronized void bar(boolean callFoo) {
        System.out.println("bar");
        if (callFoo) {
            a.foo(false);
        }
    }
}

Demo.java

public class Demo {
    public static void main(String[] args) {
    A a = new A();
    B b = new B();

    a.setB(b);
    b.setA(a);

    new Thread(() -> {
        a.foo(true);
    }).start();

    new Thread(() -> {
        b.bar(true);
    }).start();
    }
}

解决方案 :我使用的是Lock而不是synchronized

A.java

public class A {

    private final ReentrantLock lock = new ReentrantLock();
    private B b;

    public void setB(B b) {
        this.b = b;
    }

    public ReentrantLock lock() {
        return lock;
    }

    public boolean impendingExecute() {
        Boolean thisLock = false;
        Boolean otherLock = false;
        try {
            thisLock = lock.tryLock();
            otherLock = b.lock().tryLock();
        } finally {
            if (!(thisLock && otherLock)) {
                if (thisLock) {
                    lock.unlock();
                }
                if (otherLock) {
                    b.lock().unlock();
                }
            }
        }
        return thisLock && otherLock;
    }

    public void foo(boolean callBar) {
        System.out.println("foo");
        if (callBar && impendingExecute()) {
            try {
                b.bar(false);
            } finally {
                lock.unlock();
                b.lock().unlock();
            }
        }
    }
}

B.java

public class B {

    private final ReentrantLock lock = new ReentrantLock();
    private A a;

    public void setA(A a) {
        this.a = a;
    }

    public ReentrantLock lock() {
        return lock;
    }

    public boolean impendingExecute() {
        Boolean thisLock = false;
        Boolean otherLock = false;
        try {
            thisLock = lock.tryLock();
            otherLock = a.lock().tryLock();
        } finally {
            if (!(thisLock && otherLock)) {
                if (thisLock) {
                    lock.unlock();
                }
                if (otherLock) {
                    a.lock().unlock();
                }
            }
        }
        return thisLock && otherLock;
    }

    public void bar(boolean callFoo) {
        System.out.println("bar");
        if (callFoo && impendingExecute()) {
            try {
                a.foo(false);
            } finally {
                lock.unlock();
                a.lock().unlock();
            }
        }
    }
}

进行上述更改后,代码不会导致死锁。 这是实现它的正确方法(基本上,我希望审查impendingExecute()方法。)? 此外,(稍微偏离审查)是否有任何我可以遇到的真实场景?

注意 :我在Code Review上发布了这个问题,但似乎对虚拟代码的审查是偏离主题的。


I was doing some practice assignments and dabbling around with some dummy code for trying to develop a better understanding of the concepts of threads and locks. Following is a piece of code that (sometimes) goes into deadlock.

A.java

public class A {

    private B b;

    public void setB(B b) {
        this.b = b;
    }

    public synchronized void foo(boolean callBar) {
        System.out.println("foo");
        if (callBar) {
            b.bar(false);
        }
    }
}

B.java

public class B {

    private A a;

    public void setA(A a) {
        this.a = a;
    }

    public synchronized void bar(boolean callFoo) {
        System.out.println("bar");
        if (callFoo) {
            a.foo(false);
        }
    }
}

Demo.java

public class Demo {
    public static void main(String[] args) {
    A a = new A();
    B b = new B();

    a.setB(b);
    b.setA(a);

    new Thread(() -> {
        a.foo(true);
    }).start();

    new Thread(() -> {
        b.bar(true);
    }).start();
    }
}

Solution: I used Locks instead of synchronized.

A.java

public class A {

    private final ReentrantLock lock = new ReentrantLock();
    private B b;

    public void setB(B b) {
        this.b = b;
    }

    public ReentrantLock lock() {
        return lock;
    }

    public boolean impendingExecute() {
        Boolean thisLock = false;
        Boolean otherLock = false;
        try {
            thisLock = lock.tryLock();
            otherLock = b.lock().tryLock();
        } finally {
            if (!(thisLock && otherLock)) {
                if (thisLock) {
                    lock.unlock();
                }
                if (otherLock) {
                    b.lock().unlock();
                }
            }
        }
        return thisLock && otherLock;
    }

    public void foo(boolean callBar) {
        System.out.println("foo");
        if (callBar && impendingExecute()) {
            try {
                b.bar(false);
            } finally {
                lock.unlock();
                b.lock().unlock();
            }
        }
    }
}

B.java

public class B {

    private final ReentrantLock lock = new ReentrantLock();
    private A a;

    public void setA(A a) {
        this.a = a;
    }

    public ReentrantLock lock() {
        return lock;
    }

    public boolean impendingExecute() {
        Boolean thisLock = false;
        Boolean otherLock = false;
        try {
            thisLock = lock.tryLock();
            otherLock = a.lock().tryLock();
        } finally {
            if (!(thisLock && otherLock)) {
                if (thisLock) {
                    lock.unlock();
                }
                if (otherLock) {
                    a.lock().unlock();
                }
            }
        }
        return thisLock && otherLock;
    }

    public void bar(boolean callFoo) {
        System.out.println("bar");
        if (callFoo && impendingExecute()) {
            try {
                a.foo(false);
            } finally {
                lock.unlock();
                a.lock().unlock();
            }
        }
    }
}

After making the above changes, the code doesn't lead to a deadlock. Is it the proper way to implement this (Basically, I want the impendingExecute() method to be reviewed.)? Also, (deviating a bit from the review) are there any real world scenarios I can encounter this?

Note: I had posted this question on Code Review but it seems reviewal of dummy code is off-topic.


原文:https://stackoverflow.com/questions/44094584
更新时间:2023-10-28 11:10

最满意答案

除非您想为每种情况手动重置边距/填充,否则不应将容器类添加到将作为全宽的父div。

这就是我想你想要的

这里的工作代码最少

基本上,div的层次结构是div.container > div.row > div.col-xs-12/ div.col-md-6 (etc ..)..

如果你想要一个全宽度的容器,例如: div.conainer-fluid > div.container > div.row > div.col-md-6 (etc ..)。


the container class shouldn't be added to a parent div that is going to be full width unless you want to manually reset the margin/padding for each situation.

Here's what i think you want

Minimal working code here

basically, the hierarchy of divs goes div.container > div.row > div.col-xs-12/ div.col-md-6 (etc..) ..

if you want a full width container eg: div.conainer-fluid > div.container > div.row > div.col-md-6 (etc..).

相关问答

更多
  • 不,你只需要col-xs-12。 除非进行新的列分配,否则最小屏幕的列分配适用于所有较大的设备。 No, you just need col-xs-12. The column allocation for the smallest screen applies to all larger devices unless a new column allocation is made.
  • 您应该删除col-md-4和col-md-8以获得全宽查看下面的代码 $(document).ready(function() { $(".cssCircle").click(function() { var id = $(this).attr('data-target'); $(id).show(); }); });
    您的图片无法填充整个元素的原因是因为您使用background-size:contain; 。 这样,通过调整图像大小以适合高度或宽度,图像将包含在该元素内。 如果一个尺寸小于另一个,那就这样吧。 图像将变得足够高以适合元素,或者在您的情况下,足够宽以适应元素,同时保持相同的宽高比。 这也是您的图像在缩放时不调整大小的原因。 该元素的宽度也是浏览器的宽度。 因此,contains保持图像宽度与元素宽度相同,即元素宽度是浏览器的宽度。 The reason your image won't fill the ...
  • 你可以尝试用auto代替100% 喜欢这个: .band { width: auto !important; background-color: #D7EAD8; color: #323F3F; } You could try just replacing the 100% with auto like this: .band { width: auto !important; background-color: #D7EAD8; color: #323F3F; }
  • 2解决方案IMHO: 加入.row .row { margin: auto; } 集中你的块(见https://jsfiddle.net/os7frkq5/1/ ) 或者只是删除width: 100% :参见https://jsfiddle.net/os7frkq5/2/ ) 2 solutions IMHO : Add in .row .row { margin: auto; } to center your block (see https://jsfiddle.net/os7frkq5 ...
  • 除非您想为每种情况手动重置边距/填充,否则不应将容器类添加到将作为全宽的父div。 这就是我想你想要的 这里的工作代码最少 基本上,div的层次结构是div.container > div.row > div.col-xs-12/ div.col-md-6 (etc ..).. 如果你想要一个全宽度的容器,例如: div.conainer-fluid > div.container > div.row > div.col-md-6 (etc ..)。 the container class shouldn' ...
  • 你有几个拼写错误,并且没有针对正确的div,请参阅小提琴: https : //jsfiddle.net/c259LrpL/9/ set4需要是.set4 ,因为你想在set4列中定位div col-md-12 ,你应该使用下面的css。 .set4 > .row > .col-md-12{ background-color: black; height: 250px; } You have a couple typo's and where not targeting the corre ...
  • 这不是因为容器流体,而是你的行元素的边距为15px。 您的codepen已更新 只需添加 .row { margin-right: 0px; } .row { margin-right: 0px; }