volatile
modifier is required when a variable is read/written by several concurrent Threads.
Are there tools that can detect missing volatile
modifiers automatically, e.g. in Android Studio?
Algorithm:
for (Class c:allClasses) {
for (Field f:allFields) {
List<Method> allMethods = getCallHierarchy(field);
for (Method m:allMethods) {
List<Thread> threads = getCallingThreads();
if (threads.size() > 1) {
Log.w("Warning: field "+f+" is accessed by several threads.");
}
}
}
}
Code for testing the algorithm:
public class Foo {
private int a; //accessed by only one Thread - ok
private int b; //accessed by two Threads - show compiler warning
public static void main(String[] args) {
a = 10; //no race condition - ok
b = 1;
Thread th = new Thread(this::someMethod);
th.start(); //update to field "b" might stay unnoticed for mainThread
while(!isDone) {
Thread.sleep(20); //wait for the other Thread to finish
}
b += 2;
System.out.println(b); //3 or 6
}
private void someMethod() {
b += 3;
isDone = true;
}
private volatile boolean isDone = false;
}
2
Answers
No, not possible.
This is flat out incorrect.
Any field that is accessed by multiple threads, at least one which is also writing, needs ‘Happens-Before’ guarding.
volatile
is just one way to get it.synchronized
is another. There are even more exotic ways.Which code does this? That’s.. impossible to tell. It’s not possible to know at compile-time which line of code is likely to run under which thread. The way the thread model is set up, the halting problem being what it is, this is mathematically impossible to do.
This leaves precisely one route:
Have a Virtual Machine that does bookkeeping for every write to every non-volatile field in the entire system, marking down which lock(s) were active at the time, a rough timestamp, and a stacktrace.
That is an unbelievable amount of bookkeeping, even on a beefy phone with a ton of memory this is going to slow things down to a crawl. But, let’s do it, and ask the developer or tester to painstakingly wait it out whilst they hit every feature on the phone.
After the system’s been running a good long while find field accesses that time-wise appear to interleave and which have no shared active locks. Spit these accesses out: Voila, there’s a list where the developer will need to check out what’s going on and likely add some sort of locking mechanism. Could be ‘Mark the field
volatile
‘, but far more likely you should be doing something else to ensure concurrent access is properly controlled;volatile
is a bit of a loose cannon, most concurrency principles cannot be properly written withvolatile
fields.I’m not aware of any such tool, but at least now you know specifically what to look for.
You should find a tool that gives an inspection for necessity of volatile modifier, for example IntelliJ IDEA has a plugin:
Mike’s IDEA Extensions has a (Java + Kotlin) inspection Atomic can be replaced with volatile
Then you can run a named inspection in IntelliJ for the whole project using Analyze | Inspect Code.