有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我试图学习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结束的结果(无论循环长度是多少)。例如,上面的代码每次都会给我:

一, 2. 3. 4. 5. 6. 7. 8. 9 10 9 8. 7. 6. 5. 4. 3. 2. 1. 0

有时,第二个线程先启动,结果相同,但为负,因此它仍以串行方式运行

在Intellij和Eclipse中都进行了尝试,结果相同。如果重要的话,CPU有两个核心

更新:它最终变得可以复制,具有巨大的循环(从1_000_000开始),尽管仍然不是每次都可以复制,只是最终的差异很小。也似乎使循环中的操作“更重”,比如打印线程名称也使其更具可复制性。手动将睡眠添加到线程中也能起作用,但可以这么说,这会让实验变得不那么干净。原因似乎不是第一个循环在第二个循环开始之前完成,因为我看到两个循环都打印到控制台,同时继续操作,最后仍然给我0。原因似乎更像是同一变量的线程竞赛。我会更深入地研究,谢谢


共 (3) 个答案

  1. # 1 楼答案

    似乎第一个启动的线程从来没有机会在线程竞赛中获得第二个变量/第二个线程从来没有时间启动(不能确定),所以第二个线程几乎总是等待第一个循环完成

    一些繁重的操作将混合结果: TimeUnit.MILLISECONDS.sleep(100);

    *这并不总是正确的,但你在测试中很幸运

  2. # 2 楼答案

    启动线程是一个重量级的操作,这意味着它需要一些时间来执行。由于这个事实,当你开始第二个线程时,第一个线程就完成了

    为什么有时它处于“恢复顺序”的原因在于线程调度程序的工作方式。根据规范,线程执行顺序没有保证——记住这一点,我们知道第二个线程可以先运行(并完成)

    将迭代次数增加到有意义的数量,比如10000,然后看看会发生什么

  3. # 3 楼答案

    根据Brian Goetz(《实践中的Java并发性》一书的作者)的说法,这被称为幸运计时。由于没有与静态变量v的同步,很明显这个类不是线程安全的