java—两个对象如何同时获得锁?

dphi5xsq  于 2021-07-03  发布在  Java
关注(0)|答案(2)|浏览(495)

下面的代码使用lock对象以避免死锁情况。
在函数impendingbow中,两个对象如何同时获得锁:当前对象和朋友bower?

myLock = lock.tryLock();
yourLock = bower.lock.tryLock();

是因为它是两个不同的物体吗?如果是的话,这是否意味着对少数对象使用一个锁就足够了?
有人能解释一下在这个实现中我们是如何避免死锁的吗?
以下是完整代码:

public class Safelock {
    static class Friend {
       private final String name;
       private final Lock lock = new ReentrantLock();

    public Friend(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public boolean impendingBow(Friend bower) {
        Boolean myLock = false;
        Boolean yourLock = false;
        try {
            myLock = lock.tryLock();
            yourLock = bower.lock.tryLock();
        } finally {
            if (! (myLock && yourLock)) {
                if (myLock) {
                    lock.unlock();
                }
                if (yourLock) {
                    bower.lock.unlock();
                }
            }
        }
        return myLock && yourLock;
    }

    public void bow(Friend bower) {
        if (impendingBow(bower)) {
            try {
                System.out.format("%s: %s has"
                    + " bowed to me!%n", 
                    this.name, bower.getName());
                bower.bowBack(this);
            } finally {
                lock.unlock();
                bower.lock.unlock();
            }
        } else {
            System.out.format("%s: %s started"
                + " to bow to me, but saw that"
                + " I was already bowing to"
                + " him.%n",
                this.name, bower.getName());
        }
    }

    public void bowBack(Friend bower) {
        System.out.format("%s: %s has" +
            " bowed back to me!%n",
            this.name, bower.getName());
    }
}

static class BowLoop implements Runnable {
    private Friend bower;
    private Friend bowee;

    public BowLoop(Friend bower, Friend bowee) {
        this.bower = bower;
        this.bowee = bowee;
    }

    public void run() {
        Random random = new Random();
        for (;;) {
            try {
                Thread.sleep(random.nextInt(10));
            } catch (InterruptedException e) {}
            bowee.bow(bower);
        }
    }
}
dl5txlt9

dl5txlt91#

这里有两个不同的锁示例,所以取一个不会影响另一个。
当一个线程使用锁x,而另一个线程使用锁y时,就会发生死锁。然后第一个线程尝试获取锁y,并等待它被释放。同时,第二个线程尝试获取锁x,并等待它被释放。由于两个线程都在等待对方,因此操作永远无法完成,线程处于死锁状态。
这里,使用的代码 tryLock ,如果无法获取锁,则不会等待。相反,它会立即返回 false . 因为线程在获得锁之前不会阻塞,所以这个代码段永远不会导致死锁。

k97glaaz

k97glaaz2#

两个对象如何同时获得锁
两个对象表示两个独立锁。没有所谓的巨锁。有许多单独的锁。
是因为它是两个不同的物体吗?如果是,是否意味着对少数对象使用一个锁就足够了
是的,当您有一组需要同步修改的对象时,您只能使用一个锁。在这种情况下,可以选择任何对象或新的专用对象作为组的锁。
有人能解释一下在这个实现中我们是如何避免死锁的吗?
为了避免死锁,必须始终以相同的顺序锁定对象。这就是你要做的,所以你的程序没有死锁。更准确地说,当您有两个锁a和b时,其中一个线程可以先锁定a,然后锁定b,或者仅锁定b(a可能被另一个线程锁定,也可能尚未被另一个线程锁定),或者仅锁定a(b可能被另一个线程锁定,也可能尚未被另一个线程锁定)。在这些情况下决不会出现僵局。如果其中一个线程可以锁定b和a,则会出现死锁。事实并非如此。
避免死锁的一个好方法是在锁上编写依赖关系图。每个锁都是这个图中的一个对象,依赖关系是线程可以按特定顺序获取的锁。然后,要获得死锁,必须有一个有循环的等待图。但是由于等待图是依赖图的子图,并且依赖图没有循环,所以不可能出现死锁。

相关问题