当前位置: 首页 > 面试题库 >

Java中的同步如何工作

欧奇希
2023-03-14
问题内容

首先,这是一个示例:

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函数启动两个线程,每个线程都开始各自的弓箭操作。

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


问题答案:

在Java中,每个函数都Object提供了synchronize在其上锁定或锁定线程的功能。同步方法时,该方法将其对象实例用作锁。在你的示例中,方法bowbowBack都属于synchronized,并且都位于同一类中Friend。这意味着任何执行这些方法的线程都将在Friend实例上作为其锁进行同步。

一系列将导致死锁的事件是:

  1. 第一个线程调用开始alphonse.bow(gaston),这是synchronized在上alphonse Friend对象。这意味着线程必须从该对象获取锁。
  2. 第二个线程开始通话gaston.bow(alphonse),这是synchronized在上gaston Friend对象。这意味着线程必须从该对象获取锁。
  3. 现在启动的第一个线程将调用bowback并等待gaston释放锁定。
  4. 现在启动的第二个线程将调用bowback并等待alphonse释放锁定。

为了更详细地显示事件的顺序:

  1. main()开始在主要Therad中执行(称为线程1),创建两个Friend实例。到目前为止,一切都很好。
  2. 主线程使用代码开始其第一个新线程(称为线程#2)new Thread(new Runnable() { ...。线#2的呼叫alphonse.bow(gaston),这是synchronized在上alphonse Friend对象。因此,线程#2获取alphonse对象的“锁” 并进入bow方法。
  3. 时间片在这里发生,原始线程有机会进行更多处理。
  4. 与第一个线程一样,主线程将启动另一个新线程(称为线程#3)。线程#3调用gaston.bow(alphonse),它在gaston Friend对象上同步。由于还没有人获得gaston对象实例的“锁”,因此线程#3成功获取了此锁并进入了bow方法。
  5. 这里发生一个时间片,线程2获得了进行更多处理的机会。
  6. 线#2现在调用bower.bowBack(this);与bower正在该实例的引用gaston。这在逻辑上等效于的调用gaston.bowBack(alphonse)。因此,此方法synchronizedgaston实例上。该对象的锁已被获取,并由另一个线程(线程3)持有。因此,线程#2必须等待gaston释放锁定。线程进入等待状态,从而允许线程#3进一步执行。
  7. 现在bowback,线程#3进行了调用,在这种情况下,它在逻辑上与call相同alphonse.bowBack(gaston)。为此,它需要获取alphonse实例的锁,但是此锁由线程#2持有。现在,该线程已进入等待状态。

现在,你处于无法执行任何线程的位置。线程#2和线程#3都在等待释放锁。但是,如果没有Thread进展,则无法释放任何锁定。但是没有释放锁,任何线程都无法取得进展。

因此:死锁!

死锁通常取决于发生的事件的特定顺序,这可能使调试变得困难,因为它们可能难以重现。



 类似资料:
  • 问题内容: 我对Java同步有疑问。我想知道我的类中是否有三个同步方法,并且一个线程在一个同步方法中获得了锁,另外两个将被锁定吗?我问这个问题是因为我对以下陈述感到困惑。 当线程处于对象的同步方法内部时,希望执行该同步方法或对象的任何其他同步方法的所有其他线程将必须等待。此限制不适用于已经具有锁并正在执行对象的同步方法的线程。这样的方法可以调用对象的其他同步方法而不会被阻塞。当然,任何线程都可以随

  • 我对Java同步有一个疑问。我想知道如果我的类中有三个同步方法,一个线程在一个同步方法中获取锁,其他两个会被锁定吗?我问这个问题是因为我与以下语句混淆了。 当一个线程在一个对象的同步方法内部时,所有希望执行这个同步方法或该对象的任何其他同步方法的其他线程都必须等待。这个限制不适用于已经有锁并正在执行该对象的同步方法的线程。这样的方法可以调用该对象的其他同步方法而不会被阻塞。该对象的非同步方法当然可

  • 问题内容: 自从我开始用Java编程以来,我一直在想(大约一两年)。在C语言中,我们必须知道不同的方法才能正确避免线程之间的死锁,因此在同步方法之间有更多选择。 那么Java呢?当我们同步时,如何避免将线程置于死锁状态?它在内部如何运作?是否可以避免死锁,因为我们在比C(或C ++)更高的级别上进行了同步?关于Java中的死锁和同步的任何文档吗? 问题答案: 在后台,它使用两个操作码和字节码级别,

  • 问题内容: 如果我有一个带有静态方法的util类,它将调用Hibernate函数来完成基本的数据访问。我想知道是否使该方法是确保线程安全的正确方法。 我希望这可以防止对同一数据库实例的信息访问。但是,我现在确定当特定类调用以下代码时,是否阻止所有类调用以下代码。 问题答案: 为了更一般地解决这个问题… 请记住,在方法上使用同步实际上只是简写(假设类是SomeClass): 是相同的 和 是相同的

  • volley库如何在Android中同步工作?我想当volley从服务器得到响应的时候,程序的执行停止并等待volley的结果。

  • 在《有效Java》一书中: 后台线程不会在一秒钟后停止。因为提升,在JVM中优化,HotSpot服务器VM做。 您可以在以下主题中查看这一点: 为什么HotSpot会使用提升优化以下内容?。 优化过程如下: 有两种方法可以解决这个问题。 volatile的函数是 -禁止提升 -它保证任何读取该字段的线程都会看到最近写入的值 上面的代码在有效Java书中是正确的,它相当于使用来装饰。 如果此方法忽略