何时在 Java 中使用同步

2022-01-22 00:00:00 synchronization android java

我希望这将是足够的信息,所以就这样吧.如果您需要更多信息,请在评论中告诉我.

I hope this is going to be enough information, so here it goes. If you need more info, lemme know in the comments.

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

I have a class that has two inner classes. The inner classes each have two methods that call a method in the outer class. So, it looks like this:

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随时,不分先后.
  • 我目前在使用几乎同时调用 outerMethod 的现有代码(没有同步关键字)时遇到问题(我打印出一条日志消息,它们的时间戳记为千分之一秒)由不同的对象.然后我的应用程序做事"两次,因为 outerMethodHasBeenCalled 在调用 outerMethod 时仍然为假.这是不行的,这正是我想要阻止的.我的应用程序应该只做事"一次:第一次调用 outerMethod.
  • 听起来我有多个 OuterClass 实例,但请放心,这只是 OuterClass 的一个实例.
  • This is for an Android app. Instances of FirstInnerClass and SecondInnerClass are passed to a WebView as a JavaScript interface, so someMethod and someOtherMethod can be called at any time, in no particular order.
  • I currently have a problem with the existing code (without the synchronized keyword) where outerMethod is called pretty much at the exact same time (I print out a log message, and they're timestamped to the 1000th of a second) by different objects. My app then 'does stuff' twice because outerMethodHasBeenCalled is still false when outerMethod was called. This is not okay, and it is exactly what I'm trying to prevent. My app should only 'do stuff' once and only once: the first time outerMethod is called.
  • It might sound like I have multiple instances of OuterClass, but rest assured that it's only one instance of OuterClass.

重要的是,我的应用仅在第一次调用 outerMethod 时才做事"(我希望现在已经很明显了).所有后续调用基本上都被忽略了.无论哪个内部类首先调用 outerMethod - 都无关紧要.

It's important that my app 'does stuff' only the first time outerMethod gets called (I hope that's evident by now). All subsequent calls are essentially ignored. Whichever inner class calls outerMethod first -- doesn't matter.

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

So, is it appropriate to use the synchronized keyword in this case?

推荐答案

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

Yup, given what you've laid out above, I'd go with:

private synchronized void outerMethod() {
...
}

注意,这将产生阻塞调用者之一直到 outerMethod() 完成的副作用.如果这是可以接受的,那就酷.如果意图仅仅是 outerMethod() 中的代码运行一次,并且如果第一个调用者正在运行 outerMethod(),则第二个调用者不被延迟是可以的,您可以考虑:

Note, this will have the side-effect of blocking one of the callers until the outerMethod() completes. If that is acceptable, cool. If the intent is merely that the code in outerMethod() is run once, and it is OK for the second caller not to be delayed if the first caller is running outerMethod(), you might consider:

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

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

请参阅 JavaDoc for AtomicBoolean 了解那里发生了什么(假设它在 Android 的 Java 中可用).

See the JavaDoc for AtomicBoolean to grok what is going on there (assuming it is available in Android's Java).

相关文章