我正在尝试在 Java 中学习并发性,但无论我做什么,2 个线程都是串行运行的,而不是并行运行的,因此我无法复制教程中解释的常见并发问题(例如线程干扰和内存一致性错误)。示例代码:public class Synchronization {static int v;public static void main(String[] args) { Runnable r0 = () -> { for (int i = 0; i < 10; i++) { Synchronization.v++; System.out.println(v); } }; Runnable r1 = () -> { for (int i = 0; i < 10; i++) { Synchronization.v--; System.out.println(v); } }; Thread t0 = new Thread(r0); Thread t1 = new Thread(r1); t0.start(); t1.start();}}这总是给我一个从 1 开始到 0 结束的结果(无论循环长度是多少)。例如,上面的代码每次都给我:1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1 0有时,第二个线程先启动,结果相同但是否定的,所以它仍然在串行运行。在 Intellij 和 Eclipse 中都尝试过,结果相同。如果重要的话,CPU 有 2 个内核。更新:它最终通过巨大的循环(从 1_000_000 开始)变得可重现,但仍然不是每次都可以重现,只是最终差异很小。似乎也使循环中的操作“更重”,例如打印线程名称也使其更具可重复性。手动将睡眠添加到线程也有效,但它使实验不那么干净,可以这么说。原因似乎不是第一个循环在第二个开始之前完成,因为我看到两个循环在继续操作时都打印到控制台,但最后仍然给我 0。原因似乎更像是同一变量的线程竞争。我会深入研究这一点,谢谢。
3 回答
Helenr
TA贡献1780条经验 获得超4个赞
似乎第一个开始的线程从来没有机会在 Thread Race 中获得第二个变量/第二个,只是从来没有时间甚至开始(不能肯定),所以第二个几乎*总是会等到第一个循环将完成。
一些繁重的操作会混合结果: TimeUnit.MILLISECONDS.sleep(100);
*这并不总是正确的,但你在测试中很幸运
慕森卡
TA贡献1806条经验 获得超8个赞
启动一个线程是重量级的操作,这意味着它需要一些时间来执行。因此,当您启动第二个线程时,第一个线程已完成。
有时它处于“恢复顺序”的原因是线程调度程序的工作方式。根据规范,不能保证线程执行顺序 - 考虑到这一点,我们知道第二个线程有可能首先运行(并完成)
将迭代次数增加到有意义的值,例如 10000,然后看看会发生什么。
蝴蝶刀刀
TA贡献1801条经验 获得超8个赞
根据 Brian Goetz(Java Concurrency In Practice 的作者)的说法,这被称为幸运时间。由于没有同步到静态变量v
,很明显这个类不是线程安全的。
添加回答
举报
0/150
提交
取消