为了账号安全,请及时绑定邮箱和手机立即绑定

线程之间共享静态变量吗?

线程之间共享静态变量吗?

偶然的你 2019-10-08 09:49:05
我的高级Java课堂上有关线程的老师说了一些我不确定的东西。他指出,以下代码不一定会更新ready变量。根据他的说法,这两个线程不一定共享静态变量,特别是在每个线程(主线程与ReaderThread)在其自己的处理器上运行并且因此不共享相同的寄存器/缓存/等和一个CPU的情况下不会更新其他。从本质上讲,他说有可能ready在主线程中进行更新,而不是在中进行更新ReaderThread,因此ReaderThread将无限循环。他还声称该程序可以打印0或打印42。我了解如何42打印,但不是0。他提到将number变量设置为默认值时就是这种情况。我认为也许不能保证在线程之间更新静态变量,但是这对Java来说很奇怪。使ready挥发变更正此问题吗?他显示了以下代码:public class NoVisibility {      private static boolean ready;      private static int number;      private static class ReaderThread extends Thread {           public void run() {              while (!ready)   Thread.yield();              System.out.println(number);          }      }      public static void main(String[] args) {          new ReaderThread().start();          number = 42;          ready = true;      }  }
查看完整描述

3 回答

?
守候你守候我

TA贡献1802条经验 获得超10个赞

关于可见性,静态变量没有什么特别的。如果可以访问它们,那么任何线程都可以使用它们,因此您更容易看到并发问题,因为它们更容易暴露。


JVM的内存模型强加了可见性问题。这是一篇讨论内存模型以及线程如何看到写入的文章。您不能指望一个线程能够及时对其他线程可见的更改(实际上,JVM没有义务在任何时间范围内完全对您可见这些更改),除非您建立事前发生的关系。


这是该链接的引文(Jed Wesley-Smith的评论中提供):


Java语言规范的第17章定义了内存操作(例如共享变量的读写)上的事前发生关系。只有在写操作发生之前(在读操作之前),才能保证一个线程的写结果对另一线程的读取可见。同步和易失的构造,以及Thread.start()和Thread.join()方法,可以形成事前关联。尤其是:


线程中的每个动作都会发生-在该线程中的每个动作之前,该动作按程序顺序出现。


监视器的解锁(同步块或方法退出)发生在同一监视器的每个后续锁定(同步块或方法入口)之前。并且由于事前发生关系是可传递的,因此在解锁之前,线程的所有操作都发生在监视该线程的所有线程之后的所有操作之前。


在每次后续读取同一字段之前,都会对易失字段进行写操作。易失性字段的写入和读取与进入和退出监视器具有相似的内存一致性效果,但是不需要互斥锁定。


在启动线程中的任何操作之前,都会发生对启动线程的调用。


线程中的所有操作都会发生-在任何其他线程从该线程上的联接成功返回之前。



查看完整回答
反对 回复 2019-10-08
?
沧海一幻觉

TA贡献1824条经验 获得超5个赞

初始化静态基本类型变量时,java默认会为静态变量分配一个值


public static int i ;

当您像这样定义变量时,i = 0的默认值;那就是为什么有可能让你为0。然后主线程将boolean ready的值更新为true。由于ready是静态变量,因此主线程和另一个线程引用相同的内存地址,因此ready变量会更改。因此,辅助线程从while循环中退出并显示值。打印值时,数字的初始值为0。如果线程过程在主线程更新number变量之前经过了while循环。那么就有可能打印0


查看完整回答
反对 回复 2019-10-08
  • 3 回答
  • 0 关注
  • 1688 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信