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();
}
}
}
It's important to note that:
- This is for an Android app. Instances of
FirstInnerClass
andSecondInnerClass
are passed to a WebView as a JavaScript interface, sosomeMethod
andsomeOtherMethod
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 becauseouterMethodHasBeenCalled
is still false whenouterMethod
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 timeouterMethod
is called. - It might sound like I have multiple instances of
OuterClass
, but rest assured that it's only one instance ofOuterClass
.
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.
So, is it appropriate to use the synchronized keyword in this case?
Wrap everything in
outerMethod
that you want to run only once in a synchronized block:That way, the first time the method is called, only one thread will be allowed into the synchronized block at a time. The first one will execute the code in the if statement, then set
outerMethodHasBeenCalled
totrue
. The other threads will see that it is true, and skip the if code.Yup, given what you've laid out above, I'd go with:
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:
See the JavaDoc for AtomicBoolean to grok what is going on there (assuming it is available in Android's Java).