何时在Java中使用synchronized

时间:2012-02-29 07:01:17

标签: java android synchronization

我希望这将是足够的信息,所以在这里。如果您需要更多信息,请在评论中了解。

我有一个有两个内部类的类。内部类每个都有两个方法来调用外部类中的方法。所以,它看起来像这样:

public OuterClass {
    private boolean outerMethodHasBeenCalled = false;

    private void outerMethod() {
        if(!outerMethodHasBeenCalled) {
            // do stuff
        }

        outerMethodHasBeenCalled = true;
    }

    private FirstInnerClass {
        public void someMethod() {
            outerMethod();
        }
    }

    private SecondInnerClass {
        public void someOtherMethod() {
            outerMethod();
        }
    }
}

重要的是要注意:

  • 这适用于Android应用。 FirstInnerClassSecondInnerClass的实例作为JavaScript界面​​传递给WebView,因此可以随时调用someMethodsomeOtherMethod,无需特定顺序。
  • 我目前的代码存在问题(没有synchronized关键字),其中outerMethod几乎在同一时间被调用(我打印出一条日志消息,并且它们被加上时间戳到1000的第二个)由不同的对象。我的应用程序然后'做东西'两次,因为outerMethodHasBeenCalled在调用outerMethod时仍然是假的。这不好,这正是我想要阻止的。我的应用只应该只做一次“做东西”:第一次调用outerMethod
  • 听起来我可能有OuterClass的多个实例,但请放心,它只是OuterClass的一个实例。

重要的是我的应用程序'只在第一​​次outerMethod被调用时才会“填充”(我希望现在这一点很明显)。所有后续调用基本上都被忽略。无论哪个内部类首先调用outerMethod - 都无关紧要。

那么,在这种情况下使用synchronized关键字是否合适?

2 个答案:

答案 0 :(得分:19)

是的,鉴于你上面列出的内容,我会选择:

private synchronized void outerMethod() {
...
}

注意,这会产生阻塞其中一个调用者的副作用,直到outerMethod()完成。如果这是可以接受的,很酷。如果意图仅仅是outerMethod()中的代码运行一次,,如果第一个调用者正在运行outerMethod(),则第二个调用者不会被延迟,你可以考虑:< / p>

public OuterClass {
    private AtomicBoolean outerMethodHasBeenCalled = new AtomicBoolean();

    private void outerMethod() {
        if (outerMethodHasBeenCalled.compareAndSet(false, true)) {
            // do stuff
        }
    }
...

请参阅JavaDoc for AtomicBoolean以了解其中发生的事情(假设它在Android的Java中可用)。

答案 1 :(得分:7)

outerMethod中要在同步块中仅运行一次的所有内容包裹起来:

private void outerMethod() {
    synchronized (this) {
        if(!outerMethodHasBeenCalled) {
            // do stuff
        }

        outerMethodHasBeenCalled = true;
    }
}

这样,第一次调用该方法时,一次只允许一个线程进入同步块。第一个将执行if语句中的代码,然后将outerMethodHasBeenCalled设置为true。其他线程将看到它是真的,并跳过if代码。