Java中的同步如何工作

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() {

            public void run() { alphonse.bow(gaston); }

        }).start();

        new Thread(new Runnable() {

            public void run() { gaston.bow(alphonse); }

        }).start();

    }

}

我没有得到的是堵塞如何发生。main函数启动两个线程,每个线程都开始各自的弓箭操作。


“同步”到底阻止了什么?为同一对象运行的功能相同(就像我最初想的那样)?同一类的所有对象具有相同的功能?同一对象的所有同步功能?同一类所有对象的所有同步功能?


帮帮我


拉风的咖菲猫
浏览 291回答 3
3回答

子衿沉夜

在Java中,每个Object线程都提供了synchronize在其上锁定或锁定线程的能力。同步方法时,该方法将其对象实例用作锁。在您的示例中,方法bow和bowBack都属于synchronized,并且都位于同一类中Friend。这意味着任何执行这些方法的线程都将在Friend实例上作为其锁进行同步。一系列将导致死锁的事件是:第一个线程调用开始alphonse.bow(gaston),这是synchronized在上alphonse Friend对象。这意味着线程必须从该对象获取锁。第二个线程开始通话gaston.bow(alphonse),这是synchronized在上gaston Friend对象。这意味着线程必须从该对象获取锁。现在启动的第一个线程将调用bowback并等待gaston释放锁定。现在启动的第二个线程将调用bowback并等待alphonse释放锁定。为了更详细地显示事件的顺序:main()开始在主要Therad中执行(称为线程1),创建两个Friend实例。到现在为止还挺好。主线程使用代码开始其第一个新线程(称为线程#2)new Thread(new Runnable() { ...。线程#2的呼叫alphonse.bow(gaston),这是synchronized在上alphonse Friend对象。因此,线程#2获取alphonse对象的“锁” 并进入bow方法。时间片在这里发生,原始线程有机会进行更多处理。主线程启动第二个新线程(称为线程#3),就像第一个线程一样。线程#3调用gaston.bow(alphonse),它在gaston Friend对象上同步。由于还没有人获得gaston对象实例的“锁”,因此线程#3成功获取了此锁并进入了bow方法。一个时间片在这里发生,线程#2有机会进行更多处理。线#2现在调用bower.bowBack(this);与bower正在该实例的引用gaston。这在逻辑上等效于的调用gaston.bowBack(alphonse)。因此,此方法synchronized在gaston实例上。该对象的锁已被获取,并由另一个线程(线程3)持有。因此,线程#2必须等待锁定gaston被释放。线程进入等待状态,从而允许线程#3进一步执行。现在bowback,线程#3进行了调用,在这种情况下,它在逻辑上与call相同alphonse.bowBack(gaston)。为此,它需要获取alphonse实例的锁,但是此锁由线程2持有。现在,该线程已进入等待状态。现在,您处于无法执行任何线程的位置。线程#2和线程#3都在等待释放锁。但是,如果没有Thread进展,则无法释放任何锁定。但是,如果没有释放锁,则任何线程都无法取得进展。因此:死锁!死锁通常取决于发生的事件的特定顺序,这可能使调试变得困难,因为它们可能难以重现。

慕婉清6462132

同步方法与将所有这些方法代码包含在synchronized(this) {  /// code here ...}块。对于给定的对象实例o,一次只能有一个线程可以运行任何synced(o)块。尝试运行的所有其他线程都将失败,直到运行该块(具有同步锁)的线程退出该块(放弃锁)为止。在您的情况下,死锁发生在Alphonse开始在线程1中弯曲时进入同步块。然后,线程1被系统换出,因此线程2可以启动并进行Gaston弯曲。但是Gaston还不能退缩,因为它正在Alphonse上进行同步,并且线程1已经具有该锁。因此它将等待线程1离开该块。然后,系统将换回线程1,这将尝试使Alphonse退回。除非它不能这样做,因为线程2在Gaston上具有同步锁。现在这两个线程都被卡住,等待另一个线程完成弯曲,然后才能向后弯曲...

倚天杖

同一对象的所有同步功能。将方法标记为“已同步”与在方法的整个内容周围放置“已同步(this){”块非常相似。我之所以不说“相同”是因为我不知道编译器是否发出相同的字节码,但是AFAIK定义的运行时效果是相同的。死锁是经典的锁反转。一个线程锁定字母。然后(或同时在多核系统上),另一个线程锁定加斯顿。这部分要求线程的调度恰好在正确的位置进行交织。然后,每个线程(以任何顺序或同时)尝试获取另一个线程已经持有的锁,因此每个线程进入睡眠状态。双方都不会唤醒,直到对方释放其锁定,但是双方都不会释放其锁定,直到对方唤醒(或终止)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java