线程以串行而非并行方式运行

我正在尝试在 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。原因似乎更像是同一变量的线程竞争。我会深入研究这一点,谢谢。


一只名叫tom的猫
浏览 198回答 3
3回答

Helenr

似乎第一个开始的线程从来没有机会在 Thread Race 中获得第二个变量/第二个,只是从来没有时间甚至开始(不能肯定),所以第二个几乎*总是会等到第一个循环将完成。一些繁重的操作会混合结果:&nbsp;TimeUnit.MILLISECONDS.sleep(100);*这并不总是正确的,但你在测试中很幸运

慕森卡

启动一个线程是重量级的操作,这意味着它需要一些时间来执行。因此,当您启动第二个线程时,第一个线程已完成。有时它处于“恢复顺序”的原因是线程调度程序的工作方式。根据规范,不能保证线程执行顺序 - 考虑到这一点,我们知道第二个线程有可能首先运行(并完成)将迭代次数增加到有意义的值,例如 10000,然后看看会发生什么。

蝴蝶刀刀

根据 Brian Goetz(Java Concurrency In Practice 的作者)的说法,这被称为幸运时间。由于没有同步到静态变量v,很明显这个类不是线程安全的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java