无法使用静态var在java线程中获得预期的输出

时间:2016-08-06 13:48:54

标签: java multithreading

您好我正在尝试运行以下代码并与输出混淆:

它还有时给我输出如下: 答:7 C:8 B:7

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

Route::group([ 'prefix' => 'app', 'middleware' => 'auth' ], function() {
....
Route::controller('esetting', 'SettingController');
Route::get( 'esetting/mymail', 'SettingController@viewEmailAutom' ); // view for the form to display
....

1 个答案:

答案 0 :(得分:2)

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

  1. fetch i(在JVM堆栈上,JVM是堆栈计算机)
  2. 增加堆栈顶部
  3. 将堆栈顶部存储回变量i
  4. 确实,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不是易失性的,因此允许JVM优化读取访问,也就是说,它可以重新使用堆栈上已存在的println()调用的早期值。因此println()调用通常会从当前线程的角度看到值,而不是存储的值。而事情只能变得更糟糕"当字节代码被编译成可访问多个寄存器的本机代码时。

    在字节代码中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
    10. 我们得到了什么?

      • 提取6并存储7,可能会打印7
      • B抓取7并存储8,可能会打印8
      • C抓取6并存储7,可能会打印7

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