线程如何实际工作?

时间:2012-10-16 05:23:54

标签: java multithreading java-ee thread-safety

这是一个场景

我们有两个线程都访问同一段代码,并且该代码有一个变量,例如

int a = 200;

线程A输入并将其值更改为a = 300;

然后线程B访问这个变量,线程B得到200还是300?

5 个答案:

答案 0 :(得分:2)

不保证两个线程以任何固定顺序执行; A中的任何操作都可以在B中的任何操作之前(假设操作仍在其自己的线程中顺序流动)。

因此,如果没有同步,A可能会在B访问它之前或之后更改其值。如果A在B之前改变它,则B看到300;否则,B看到200。

答案 1 :(得分:1)

下面的状态图表描述了线程状态。

enter image description here

  • Runnable - 等待线程调度程序根据线程优先级选择执行它。
  • 正在运行 - 处理器正在主动执行线程代码。它一直运行直到它被阻塞或自愿 用这个静态方法Thread.yield()放弃了它。由于上下文切换开销,yield()应该 不经常使用。
  • 等待 - 线程在等待文件I / O等外部处理完成时处于阻塞状态。
  • 睡眠 - 使用此重载方法强制Java线程进入休眠状态(暂停): Thread.sleep(milliseconds), Thread.sleep(milliseconds, nanoseconds);
  • 在I / O上阻塞 - 在读取数据字节等I / O条件发生变化后,将移至runnable。
  • 同步时阻止 - 获取锁定时将移至Runnable。
  • - 主题已完成。

关于你的例子,我们不知道线程B将占用200或300.如果你同时启动两个线程,因为你的方法将被同步,线程B应该看到200(如果它将是第一个或300)。

答案 2 :(得分:1)

由于编译器优化,线程可以缓存数据,第二个线程可能看不到第一个线程更改。这就是“volatile”用于共享数据以避免多线程环境中的问题

附录 - 我说的是线程中变量变化的可见性,而不是同步。

答案 3 :(得分:0)

如果你的线程同时访问你的代码,它将根据jvm级别的线程优先级发生。我们无法保证哪个线程将访问代码。如果它是同步的,则线程B必须等到线程A释放资源。

答案 4 :(得分:0)

上述执行的结果取决于一致性模型。

在顺序一致性模型中,执行的结果是所有指令都以某种全局顺序执行。在这种情况下,threadB将获得值300.

但是,现代机器使用较弱的一致性模型,其中所有同步(内存栅栏指令)操作仅以全局顺序顺序发生。

如果在threadA的存储完成后发生了threadB的加载,则threadB将获得值= 300.这由高速缓存一致性协议保证。 但是,如果threadB的加载指令发生在threadA的存储之前/之后(由于某些优化),则threadB中的共享变量的值是未定义的。这将是在总线操作中threadB的加载和threadA的存储之间的竞争条件的结果。