java - 无法使用 static var 在 java 线程中获得预期输出

标签 java multithreading

嗨,我正在尝试运行下面的代码,但对输出感到困惑:

它有时也会给我输出如下: 答:7 中:8 乙:7

这里,一旦静态值更改为 8,之后 B 线程将要运行并打印其值 7,这是怎么可能的!我的意思是 i 是静态变量,那么它只有一个副本。

public class ThreadStaticTest implements Runnable {

    static int i = 5;

    public static void main(String[] args) {
        ThreadStaticTest obj = new ThreadStaticTest();
        Thread t1 = new Thread(obj);
        Thread t2 = new Thread(obj);
        Thread t3 = new Thread(obj);

        t1.setName("A");
        t2.setName("B");
        t3.setName("C");

        t1.start();
        t2.start();
        t3.start();
    }

    @Override
    public void run() {
        i++;
        System.out.println(Thread.currentThread().getName()+" : "+i);
    }
}

最佳答案

想想i++作为三种不同的操作:

  1. 获取i (到了JVM栈上,JVM就是一个栈机)
  2. 增加堆栈顶部
  3. 将堆栈顶部存储回变量 i .

确实,OpenJDK 8 的 javac 编译 run()方法进入:

public void run();
   Code:
      0: getstatic     #11                 // Field i:I
      3: iconst_1
      4: iadd
      5: putstatic     #11                 // Field i:I

此外,因为 i不是 volatile 的,允许 JVM 优化读取访问,也就是说,它可以重新使用堆栈上已有的值 println()称呼。所以println() call 通常会从当前线程的角度看到该值,而不是存储的值。当字节码被编译成可以访问多个寄存器的 native 代码时,事情只会变得“更糟”。

有一个getstatic println() 之前调用在字节代码中,但是——正如所指出的——它可能会被优化掉。无论如何,无法保证它会读取什么值。您甚至无法确定打印的值是同一线程之前看到的值。

现在,考虑以下操作顺序,假设 i = 6 .

  1. 线程 A:获取 i
  2. 线程 C:获取 i
  3. 线程 A:增量 i
  4. 主题 A:商店 i
  5. 线程 B:获取 i
  6. 线程 B:增量 i
  7. 主题 B:商店 i
  8. 线程 C:增量 i
  9. 线程 C:商店 i

我们得到什么?

  • A 获取 6和商店7 ,可能会打印 7 .
  • B 获取 7和商店8 ,可能会打印 8 .
  • C 获取 6和商店7 ,可能会打印 7 .

每次运行你应该得到不同的结果,因为没有什么可以保证这个执行顺序。

关于java - 无法使用 static var 在 java 线程中获得预期输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38804962/

相关文章:

c++ - 添加用于监听网络的新线程时应用程序卡住

java - 同步数据读/写到/从主存储器

java - 处理@DiscriminatorColumn 中的 NULL 值

java - Maven 使用错误版本的 android 进行编译

java - 您如何确定 App Engine 数据库请求的可接受响应时间?

Pythonistas,请帮助将其转换为利用 Python 线程概念

java - 在java中创建临时文件夹

java - 使用 filereader 和 filewriter 读取和写入文件

java - 多线程最佳实践: constraining tasks newFixedThreadPool

c# - 任务调度器(Task.Factory)和控制线程数