【问题标题】:Order in which our source code is run when using different threads使用不同线程时我们的源代码运行顺序
【发布时间】:2020-09-15 21:59:13
【问题描述】:

当我第一次开始学习 Java 时,我了解到 代码 是从 topbottom 读取的。无需编写代码来涵盖该解释,因为我想你们都明白了。

但是当我使用multi-threading 时会发生什么?假设我有这个简单的例子:

public class Tester {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            executorService.execute(new WorkingClass());
        }
        System.out.println("rest od code..");
        executorService.shutdown();
    }
}

class WorkingClass implements Runnable{
    @Override
    public void run() {
        System.out.println("working");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我正在使用 singleThreadExecutor,所以 1 个线程 应该完成这 5 个任务。我希望我的 for 循环 会首先运行,在 控制台 中打印 "rest od code.." 之前至少打印一个 "working"。我错了。我的结果总是这样:

rest od code..
working
working
working
working
working

谁能告诉我,在'rest of code' 之前的控制台 中至少有一个'working' 吗?是否有可能代码运行得如此之快以至于在到达('rest of code')之前没有机会实际运行任何run() method

[注意] 任何修改都将有助于改进此问题。

【问题讨论】:

  • 创建新实例的开销可能比当前线程慢
  • 您应该多次运行此命令,看看是否有任何不同
  • @OneCricketeer 这正是我所期待的。我只是不想做出任何错误的假设,所以我不会学到错误的东西。是的,我多次运行它:)
  • 仅供参考: “我了解到代码是从上到下阅读的。” -- 允许编译器重新排序语句,只要它不改变“单线程透视”和其他限制的结果。这不是你“问题”的原因;这是线程创建/调度开销。
  • 在多线程中永远不要假设执行顺序。

标签: java multithreading java-threads


【解决方案1】:

不同的线程独立运行。无法保证您的主线程与其创建的任何“Runnables”之间的相对顺序。

这与代码是否从上到下“读取”无关;这不是一个有用的执行概念。这是一个非自上而下执行的简单非线程示例:

   void method1() {
       method2();
       System.out.println("one");
   }

   void method2() {
       System.out.println("two");
   }

回到手头的问题:您会注意到“执行”的 documentation 指的是在“未来某个时间”运行 Runnable。

实际上,这可能类似于将条目放入队列然后唤醒线程。启动和运行线程通常需要比直线代码路径更多的机器指令。

所以,是的,你的“跑得这么快”的解释或多或少是对的,只是“这么快”并不是真的快得令人眼花缭乱。

【讨论】:

  • 有道理。我想我明白了。所以有2个线程(主线程和线程1)。在我的例子中,主线程执行打印语句的速度比线程 1 执行任何“工作”的速度要快,对吧?
  • 是的,就是这样。这里更深层次的教训是,如果事情以特定的顺序发生很重要(在你的情况下不是这样),那么你必须在代码中做出规定以强制该顺序 - 这就是有趣/恐怖的地方多线程编程进来了。
【解决方案2】:

线程在并发执行(主线程和工作线程),尝试在main方法中的println之前暂停主线程执行一小会儿,结果会不一样。

Thread.sleep(1000);
System.out.println("rest od code..");
executorService.shutdown();

重复运行以及您的工作线程在主线程暂停时执行的可能性很大。

期待的是内存一致性效应:

“在将 Runnable 或 Callable 任务提交给 ExecutorService 之前线程中的操作发生在该任务采取的任何操作之前,这反过来又发生在通过 Future.get() 检索结果之前”

【讨论】:

    猜你喜欢
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    • 2020-11-07
    • 1970-01-01
    相关资源
    最近更新 更多