死锁在哪里?

Din*_*mar 1 java multithreading

这是java docs for deadlock的教程.我没有得到线程被阻止的地方.因为它同步我以为只有一个线程会进入弓形.但两人都进了弓.[等待[但什么时候?]]

那问题在哪里?

当我添加注释[print statements to trace].没有僵局.怎么样?

public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s" + "  has bowed to me!%n", this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s"
                + " has bowed back to me!%n",
                this.name, bower.getName());            
        }
    }

    public static void main(String[] args) {
        final Friend alphonse =
            new Friend("Alphonse");
        final Friend gaston =
            new Friend("Gaston");
        new Thread(new Runnable() {
            @Override
            public void run() { 
               // System.out.println("Thread 1");
                alphonse.bow(gaston); 
               // System.out.println("Th: gaston bowed to alphonse");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() { 
              //  System.out.println("Thread 2");
                gaston.bow(alphonse);
              //  System.out.println("2.gaston waiting alph bowed");
            }
        }).start();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是:

Alphonse: Gaston  has bowed to me!
Gaston: Alphonse  has bowed to me!
Run Code Online (Sandbox Code Playgroud)

没有人回头!

Dav*_*hun 6

这里有两个重要的事情要理解:1)每个并发运行的线程在做什么?2)涉及哪些锁?

最后,您创建了两个Friend类的实例:alphonse和gaston.每个对象都拥有自己的锁.所以有两个锁:alphonse的锁和gaston的锁.当您输入对象的同步方法时,它会锁定该对象的锁定.当synchronized方法返回时,锁被释放(解锁).

现在的线程.你的第一个线程,让我们称它为Alphone的线程(注意大写A来区分线程与对象,alphonse)这样做:("A:"表示这是Alphonse的线程.)

A: alphonse.bow(gaston) - acquires alphonse's lock
A: gaston.bowBack(alphonse) - acquires gaston's lock
A: both methods return, thus releasing both locks
Run Code Online (Sandbox Code Playgroud)

同时,加斯顿的主题是:("G:"表示这是加斯顿的主题.)

G: gaston.bow(alphonse) - acquires gaston's lock
G: alphonse.bowBack(gaston) - acquires alphonse's lock
G: both methods return, thus releasing both locks
Run Code Online (Sandbox Code Playgroud)

现在我们可以将这两个信息放在一起以得出答案.线程可以以不同的顺序交错(即,它们的事件发生).例如,如果事件按此顺序发生,则会发生死锁:

A: alphonse.bow(gaston) - acquires alphonse's lock
G: gaston.bow(alphonse) - acquires gaston's lock
G: attempts to call alphonse.bowBack(gaston), but blocks waiting on alphonse's lock
A: attempts to call gaston.bowBack(alphonse), but blocks waiting on gaston's lock to
Run Code Online (Sandbox Code Playgroud)

在这种情况下,每个线程都被阻塞,等待获取另一个线程持有的锁.但是,两个线程都不会释放它所持有的锁,因为它必须完成它的方法才能这样做,因为它被阻塞等待另一个线程所以它无法完成.因此他们陷入困境 - 陷入僵局.

但是,另一种可能的交错(事件顺序)是其中一个线程在另一个线程真正开始之前完成的交错,如下所示:

A: alphonse.bow(gaston) - acquires alphonse's lock
A: gaston.bowBack(alphonse) - acquires gaston's lock
A: both methods return, thus releasing both locks
G: gaston.bow(alphonse) - acquires gaston's lock
G: alphonse.bowBack(gaston) - acquires alphonse's lock
G: both methods return, thus releasing both locks
Run Code Online (Sandbox Code Playgroud)

在这种情况下,没有死锁.当您添加println并且没有死锁时,很可能发生的事情是额外println的额外延迟会影响线程运行的调度和/或速率,因此您可以获得这种交错,而不是死锁.

当结果取决于并发事件的顺序(即,它们的调度或它们运行的​​速率)时,称为"竞争条件".例如,在此程序中,哪个线程首先打印输出取决于它们的计划顺序或它们运行的​​速率.线程死锁是否也取决于此.因此,通过扰乱该速率(例如,通过添加额外指令),您可能会影响比赛的结果 - 但这并不意味着比赛已经消失.

并非所有竞争条件都有可能导致死锁.但是,根据我的经验,死锁只发生在竞争条件下.(也许有人知道可以评论是否一定是这种情况,或者通常只是这种情况?)

死锁一开始并不容易理解; 我尽力解释,但如果您对我的帖子有任何后续问题,请告诉我.:)


Boh*_*ian 5

首先,调用System.out.println()会带来大量资源,因此会在处理过程中产生有效的延迟,从而人为地导致/避免并发问题.不要过多地阅读添加打印效果.

然后,当线程A锁定X然后锁定Y时发生死锁,并且同时线程B使用位置Y然后锁定X.如果两者都得到它们的第一个锁,则两者都不能继续=死锁.

在你的情况下,该方法bow()锁定它被调用的实例,但是然后从该锁内调用bowee的bow方法:同步锁定实例,因此两个单独的实例都可以获得它们的第一个锁.第二个锁在另一个实例上,因此两个线程都在等待另一个thread = deadlock持有的锁.