当一个变量被多个并发线程读写时需要volatile
修饰符
是否有工具可以自动检测缺失的volatile
修饰符,例如在Android Studio?
算法:
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.");
}
}
}
}
算法测试代码:
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;
}
不可能。
volatile
修饰符当一个变量被多个并发线程读写时需要。
这是完全错误的。
任何被多个线程访问的字段,至少有一个正在写,都需要'Happens-Before'保护。
volatile
只是得到它的一种方法。synchronized
是另一个。还有更奇特的方法。
哪个代码做这个?这是. .很难说。在编译时不可能知道哪一行代码可能在哪个线程下运行。线程模型的建立方式,暂停问题是什么,这在数学上是不可能做到的。
这只剩下一条路由:
让一个虚拟机为每个做记录,写入整个系统中的每个非易失性字段,标记当时哪些锁是活动的,一个粗略的时间戳和堆栈跟踪。
这是一个令人难以置信的大量的簿记,即使是在一个拥有大量内存的强大手机上,这也会使事情变得缓慢。但是,让我们这样做,并要求开发人员或测试人员在他们测试手机上的每个功能时煞费苦心地等待。
在系统运行了很长一段时间后,发现字段访问在时间上似乎是交错的,并且没有共享的活动锁。说出这些访问:瞧,有一个列表,开发人员将需要检查发生了什么,并可能添加某种锁定机制。可能是"标记字段volatile
",但更有可能的是你应该做一些其他的事情来确保并发访问得到适当的控制;volatile
有点松散,大多数并发原则不能用volatile
字段正确地编写。
我不知道有任何这样的工具,但至少现在你知道具体要找什么了。
你应该找一个工具来检查volatile修饰符的必要性,例如IntelliJ IDEA有一个插件:
Mike的IDEA Extensions有一个(Java + Kotlin)检查Atomic可以替换为volatile
然后你可以在IntelliJ中使用Analyze | Inspect Code对整个项目运行一个命名的检查。