【问题标题】:Java: how to check automatically which fields require a volatile modifier?Java:如何自动检查哪些字段需要 volatile 修饰符?
【发布时间】:2022-06-13 15:21:09
【问题描述】:

当一个变量被多个并发线程读/写时,需要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;
}

【问题讨论】:

  • 这似乎需要完整的流分析来确定 (a) 哪些方法是从哪些对象上的哪些线程调用的,以及 (b) 是否使用了任何其他同步。而且由于线程是一种运行时现象,即使那样它也不能是完整的。
  • 我的意思是,如果您使用其他形式的锁定,则不需要它,根据您需要的确切并发语义,它是不够的,因此这样的标志可能会给用户一种非常错误的安全感。

标签: java android-studio volatile


【解决方案1】:

不,不可能。

当一个变量被多个并发线程读/写时,需要volatile修饰符。

这是完全错误的。

由多个线程访问的任何字段,至少一个也在写入的字段需要“Happens-Before”保护。

volatile 只是一种 获得它的方式。 synchronized 是另一个。还有更多奇特的方式。

哪个代码可以做到这一点?那是..不可能说的。在编译时不可能知道哪行代码可能在哪个线程下运行。线程模型的设置方式,即停机问题,这在数学上是不可能做到的。

这正好留下一条路线:

拥有一个虚拟机,为整个系统中的每个写入到每个非易失性字段进行记账,标记当时哪些锁处于活动状态、粗略的时间戳和堆栈跟踪。

这是一个难以置信的簿记量,即使在具有大量内存的强大手机上,这也会让事情慢下来。但是,让我们这样做,并要求开发人员或测试人员在他们使用手机上的每个功能时苦苦等待。

在系统运行了很长时间之后,发现字段访问在时间上似乎是交错的,并且没有共享的活动锁。吐出这些访问:瞧,有一个列表,开发人员需要在其中检查发生了什么,并可能添加某种锁定机制。可能是“标记字段volatile”,但更有可能您应该做其他事情以确保正确控制并发访问; volatile 有点松散的大炮,大多数并发原理都不能用volatile 字段正确编写。

我不知道有任何此类工具,但至少现在您知道具体要寻找什么。

【讨论】:

  • 听起来您正在寻找 Java TSAN,尽管它在 OpenJDK 上运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 2017-10-04
  • 1970-01-01
  • 2016-11-10
  • 2020-02-03
  • 2017-03-07
相关资源
最近更新 更多