使用不同线程时源代码运行的顺序。

huangapple go评论81阅读模式
英文:

Order in which our source code is run when using different threads

问题

当我刚开始学习关于Java编程时,我了解到代码是从顶部底部进行阅读的。不需要编写代码来解释这一点,因为我猜您都明白。

但是当我使用多线程时会发生什么呢?假设我有这个简单的例子:

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("其余代码...");
        executorService.shutdown();
    }
}

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

我正在使用singleThreadExecutor,所以1个线程应该执行这5个任务。我原以为我的for循环会首先运行,在控制台中至少打印一次"正在工作",然后再打印"其余代码..."。但事实并非如此。我的结果始终是这样的:

其余代码...
正在工作
正在工作
正在工作
正在工作
正在工作

有人能告诉我为什么在打印"其余代码..."之前,至少有一个"正在工作"不会在控制台中打印出来吗?有可能代码运行得如此之快,以至于在达到"其余代码..."之前根本没有机会实际运行任何run()方法吗?

【注】欢迎对这个问题进行任何编辑以帮助改进。

英文:

When I first started learning about Java, I learnt that code is read from top to bottom. No need to make a code to cover that explanation as I guess you all understand it.

But what happens when I am using multi-threading? Say I have this simple example:

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

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

I am using singleThreadExecutor, so 1 thread should do those 5 tasks. I was expecting that my for loop would run first, printing at least one &quot;working&quot; before printing &quot;rest od code..&quot; in console. I was wrong. My result is always this:

rest od code..
working
working
working
working
working

Can someone tell me how isn't at least one &#39;working&#39; printed in console before &#39;rest of code&#39;? Is it possible that code run so fast that it didn't get a chance to actually run any run() method before reaching ('rest of code')?

[NOTE] Any edit would be appreciated to help improve this question.

答案1

得分: 2

不同的线程独立运行。关于主线程和它创建的任何“Runnables”之间的相对顺序,没有任何保证。

这与代码是否从上到下“读取”无关;这对于执行不是一个有用的概念。这里有一个简单的非线程示例,展示了非从上到下的执行顺序:

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

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

回到手头的问题:您会注意到“execute”的文档是指在“将来的某个时间”运行可运行对象。

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

所以,是的,您的“运行得如此快”的解释在某种程度上是正确的,只是“如此快”并不是真正的极快。

英文:

Different threads run independently. There are no guarantees about relative order between your main thread and any of the 'Runnables' it creates.

This is nothing to do with whether code is 'read' from top to bottom; that's not a useful concept for execution. Here is a trivial non-thread example of non-top-to-bottom execution:

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

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

Back to the issue at hand: you'll notice the documentation for 'execute' refers to running the Runnable at 'some time in the future'.

In reality, that's probably something like putting an entry on a queue and then waking up a thread. Getting the thread up and running typically takes more machine instructions that the straight-line code path.

So, yes, your 'runs so fast' explanation is more-or-less on the mark, except that 'so fast' isn't really blindingly fast.

答案2

得分: 1

线程正在并发执行(主线程和工作线程),在主方法中的println语句之前尝试暂停主线程的执行片刻,结果会有所不同。

Thread.sleep(1000);
System.out.println("其余代码...");
executorService.shutdown();

重复运行,主线程暂停时工作线程执行的机会很大。

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

“在将Runnable或Callable任务提交给ExecutorService之前,线程中的操作先于任务执行的任何操作,而这反过来会先于通过Future.get()检索结果的任何操作”。

英文:

Threads are executing concurrently (main thread and the worker thread), try pause the main thread execution for a short while before the println in main method, and the results will be different.

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

Repeat the run and the chances that your worker thread execute while the main thread pause is highly likely.

What to expect is the memory consistency effect:

"Actions in a thread prior to the submission of a Runnable or Callable task to an ExecutorService happen-before any actions taken by that task , which in turn happen-before the result is retrieved via Future.get()"

huangapple
  • 本文由 发表于 2020年9月16日 05:59:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/63910393.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定