0

这是一个场景

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

诠释a = 200;

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

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

4

5 回答 5

2

不保证两个线程以任何固定顺序执行;A 中的任何操作都可以先于 B 中的任何操作(前提是这些操作仍然在它们自己的线程中按顺序流动)。

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

于 2012-10-16T05:29:59.100 回答
1

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

在此处输入图像描述

  • Runnable - 等待轮到它被线程调度程序根据线程优先级选择执行。
  • Running — 处理器正在积极执行线程代码。它一直运行直到它被阻塞,或者使用这个静态方法 Thread.yield() 自愿放弃轮到它。由于上下文切换开销,不应频繁使用 yield()。
  • 等待— 线程在等待某些外部处理(例如文件 I/O)完成时处于阻塞状态。
  • 休眠— Java 线程通过这个重载方法被强制进入休眠(挂起): Thread.sleep(milliseconds), Thread.sleep(milliseconds, nanoseconds);
  • Blocked on I/O — 将在 I/O 条件(如读取数据字节等)发生变化后转为可运行状态。
  • 同步时阻塞- 获取锁时将移动到 Runnable。
  • Dead — 线程已完成工作。

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

于 2012-10-16T05:38:13.937 回答
1

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

附录-嗯,我说的是跨线程的变量更改的可见性,而不是同步。

于 2012-10-16T05:41:07.890 回答
0

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

于 2012-10-16T05:37:33.667 回答
0

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

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

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

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

于 2012-10-16T05:40:53.957 回答