【问题标题】:Multithreading start method多线程启动方法
【发布时间】:2014-05-01 15:06:25
【问题描述】:

这是一个普通的线程程序

class Counter implements Runnable {
    private int currentValue;
    public Counter() { currentValue = 0; }
    public int getValue() { return currentValue; }
    public void run() { // (1) Thread entry point
    try {
      while (currentValue < 5) {
      System.out.println(Thread.currentThread().getName() + ": " + (currentValue++)); // (2) Print thread name.
     Thread.sleep(250); // (3) Current thread sleeps.
          }
        } catch (InterruptedException e) {
           System.out.println(Thread.currentThread().getName() + " interrupted.");
           }
           System.out.println("Exit from thread: " + Thread.currentThread().getName());
         }
      }

 //_______________________________________________________________________________
public class Client {
    public static void main(String[] args) {
    Counter counterA = new Counter(); // (4) Create a counter.
    Thread worker = new Thread(counterA, "Counter A");// (5) Create a new thread.
    System.out.println(worker);
    worker.start(); // (6) Start the thread.
    try {
       int val;
       do {
         val = counterA.getValue(); // (7) Access the counter value.
         System.out.println("Counter value read by " + Thread.currentThread().getName()+ ": " + val); // (8) Print thread name.
         Thread.sleep(1000); // (9) Current thread sleeps.
           } while (val < 5);
        } catch (InterruptedException e) {
          System.out.println("The main thread is interrupted.");
       }
       System.out.println("Exit from main() method.");
     }
    }

输出是

Thread[Counter A,5,main]
Counter value read by main thread: 0
Counter A: 0
Counter A: 1
Counter A: 2
Counter A: 3
Counter value read by main thread: 4
Counter A: 4
Exit from thread: Counter A
Counter value read by main thread: 5
Exit from main() method.

我的问题是,即使工作线程最初在主线程进入它的 try 块之前启动,主线程执行首先开始,然后当主线程进入睡眠状态时,子线程开始运行。

如这张图片(摘自《Java SCJP 认证程序员指南:综合入门第三版》) 作者:Khalid A Mughal,Rolf W Rasmussen)描述了当线程上的 start 方法被调用时,它立即返回。

请解释这一点,为什么在调用 start 方法时它会立即返回,并且线程是否在调用 start 方法时启动。就像这里调用 start 方法一样,它不会调用类的 run 方法。那么线程实际上是什么时候开始的呢?

还要解释一下“对 start() 方法的调用是异步的。”

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    您的整体分析中缺少三件事。

    1. 对线程的启动方法的调用是顺序的而不是并行的。它对线程的运行方法的调用是并发的。因此,如果您在调用 start 的 main 方法中有 5 个语句,则不会首先调用 5ht。这就是 JVM 规范为您提供的“发生在之前”的保证。然而 1 first 的 run 方法可能在调用第二个 start 语句之前或之后被调用。这更多取决于 CPU 时间切片问题,而不是程序执行问题。
    2. 当您的程序中运行超过 1 个线程时,输出顺序是不确定的。那是因为它们并行运行。你永远无法确定同一个程序会在两台机器上以相同的顺序运行,甚至在同一台机器上运行两次。在您的问题中,您仅发布了 1 个输出。将程序依次运行 20 次并匹配输出。我敢肯定 2 或 3 会完全不同。
    3. 最后,您的分析基于并发代码的顺序或执行。那是最大的笨蛋程序员。并发程序从不打算以特定的顺序或顺序运行。只需尝试使您的 Runnable 工作成为原子互斥任务(与程序的其余部分甚至其他 Runnable 互斥)并跟踪其自身的执行。不要将线程混合在一起。

    【讨论】:

    • 我已经阅读了这些内容,并且我知道并发代码并不意味着按特定顺序运行。关于你的第二点。忘记 20 次吧,我已经运行了 100 次,并且在同一台机器上得到了相同的输出。我同意不同机器上的输出可能不同。但这不是我的问题。我只是在问 start 方法是如何工作的..!
    • 输出是相同的,因为有了这么多的操作,而且它们花费的时间太短,几乎是确定性的。要获得实际不同的结果,您需要在不同负载的不同机器上运行它
    • 有时在 windows/linux 上会有一个特定的执行顺序。尝试在您的系统上增加一些繁重的负载并尝试多次运行您的代码。 Start 将始终按顺序执行。但是一旦开始完成(您的新线程已创建并且现在有一个单独的执行堆栈),您的新线程可能会直接进入 Runnable 状态。这取决于你的系统。运行将始终同时运行。
    • 尝试在循环中运行 100 万跳,然后在其间休眠 2 毫秒。
    • 我要问的是,当调用 start 方法时,它是否等待线程创建然后进入它的 run 方法,或者它返回到主线程并等待线程创建然后调用run方法。
    【解决方案2】:

    您不能直接强制执行/运行哪个线程。一旦启动它,它就会在较低级别(通常由操作系统)处理,结果在不同的机器上甚至在不同的执行中可能会有所不同。如果你需要更多的控制,你需要使用一些同步机制。

    【讨论】:

    • 一旦我启动它立即返回到主线程,这就是我们可以在输出中看到的。
    【解决方案3】:

    线程没有在调用start() 下同步启动。它稍后发生(异步)。换句话说,仅仅因为你调用了start() 并不意味着线程已经启动。

    他们为什么以及如何实现所有细节,这可能取决于 JVM 和/或操作系统实现。

    【讨论】:

    • 那么实际发生了什么。当我调用 start 方法时,它会回到主线程,并继续执行它的语句。
    • "它稍后发生(异步)。"什么时候发生?正如理论所说,当您在线程上调用 start 方法时,它会执行 Runnable 对象的 run() 方法。
    • @user2963317 它的作用远不止于此!一次 - 它实际上会创建一个操作系统线程,这不会立即发生(或重用线程,取决于 JVM 等)。当你调用 start 时,线程的实际创建就开始了,当它完成时,调用 run 。正如您在发布的图片中看到的那样,调用 run 时与原始线程(称为 start)中发生的事情无关。在您的情况下,由于您的操作都是轻量级的,因此 Main 可以在调用 run 之前执行更多操作
    • 啊..!这意味着不必每次在线程上调用 start 方法时,它都会返回启动它的线程(这里是主线程),而是可以直接调用 run 方法而不返回启动它的线程(这里这是主线程)
    猜你喜欢
    • 2023-03-27
    • 2013-10-03
    • 1970-01-01
    • 2021-11-29
    • 1970-01-01
    • 2023-02-11
    • 2023-04-10
    • 2018-03-27
    • 1970-01-01
    相关资源
    最近更新 更多