多线程之join方法

一.前言:

       在很多情况下,我们都是通过主线程创建并启动子线程的,如果子线程中需要耗费大量的时间计算的话,主线程往往会比子线程先结束,这个时候就会导致有时候主线程想获取子线程计算之后的结果,但是却获取不到。这个时候,我们就可以通过join方法来解决这个问题。

二.join方法的作用:

join方法的作用是使所属的线程对象x正常执行run()方法中的任务,而使当前线程z进行无限期的阻塞,等待线程x销毁后再继续执行线程z后面的代码。方法join具有使线程排队运行的作用,有些类似同步的运行效果。

下面看一个例子:

public class MyThread extends Thread{
    @Override
    public void run() {
        int sencondValue = (int)(Math.random()*1000);
        System.out.println(sencondValue);
        try {
            Thread.sleep(sencondValue);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        myThread.join();
        System.out.println("当对象myThread执行完毕后再执行");
    }
}

运行结果:join的意思是使得放弃当前线程的执行,并返回对应的线程,例如上面代码的意思就是:程序在main线程中调用myThread线程的join方法,则main线程放弃cpu控制权,并返回myThread线程继续执行直到线程myThread执行完毕。所以结果是线程myThread执行完后,才到主线程执行,相当于在main线程中同步线程myThreadmyThread执行完了,main线程才有执行的机会 此外,join方法和interrupt方法相遇的时候会抛出异常。

此外,还有join(long millis)方法,指定要等待多长时间。

三.join的实现原理:

查看join方法源码:

/**
     * Waits for this thread to die.
     *
     * <p> An invocation of this method behaves in exactly the same
     * way as the invocation
     *
     * <blockquote>
     * {@linkplain #join(long) join}{@code (0)}
     * </blockquote>
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final void join() throws InterruptedException {
        join(0);
    }
public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

可以看出,join方法实际上是通过调用wait方法, 来实现同步的效果的。例如,A线程中调用了B线程的join方法,则相当于A线程调用了B线程的wait方法,在调用了B线程的wait方法后,A线程就会进入阻塞状态,因为它相当于放弃了CPU的使用权。需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。

四.join方法和synchronized、sleep方法的区别:

1.从上面的源码我们可以看出,join(long millis)是通过在内部使用wait(long millis)方法来实现的,所有它其实是具有释放锁的特点的,在执行完;而sleep(long millis)是不释放锁的,也就是如果有Synchronized同步块,其他线程仍然不能访问共享数据。注意该方法要捕获异常。

2.join在内部使用wait()方法进行等待,而synchronized关键字使用的是“对象监控器”原理做同步,具体可以看这个synchronized原理

 

参考:https://www.2cto.com/kf/201608/543154.html

           https://www.cnblogs.com/lcplcpjava/p/6896904.html

 

<think>好的,用户想了解C#多线程编程中的Join方法。首先,我需要回忆一下Thread类中的Join方法的作用。记得Join方法主要是用来阻塞当前线程,直到被调用的线程执行完毕。也就是说,当在一个线程中调用另一个线程Join方法时,当前线程会等待,直到另一个线程完成。 接下来,应该考虑用户可能的背景。他们可能是刚开始学习多线程编程,可能对线程同步的概念不太熟悉。需要解释清楚为什么需要Join方法,以及它在实际中的应用场景。比如,主线程需要等待子线程完成后再继续执行,这时候就可以用Join。 然后,要确保用简单易懂的中文解释,避免使用太多专业术语,或者如果用了术语,要适当解释。例如,阻塞当前线程是什么意思,可能需要举例说明。 另外,用户提到的系统级指令要求使用LaTeX格式的行内公式,不过这个问题可能不涉及数学表达式,所以可能不需要用到。但需要检查是否有地方可能用到,比如如果有示例代码中的变量,可能不需要数学公式,所以可以忽略这部分。 需要结构清晰,分步骤或者分点说明。可能先定义Join方法,然后说明其作用,接着给出一个简单的代码示例,最后总结使用场景和注意事项。 还要注意LaTeX的正确使用,如果有变量或代码内的符号,可能需要用$包围,但C#代码中的变量一般不需要,所以可能不需要处理。但需要确认用户的要求,他们提到行内数学表达式必须用$...$,但代码示例中的变量可能不属于数学表达式,所以正常用代码块即可。 另外,用户要求用中文回答,所以所有术语都要保持中文,比如“线程”而不是“Thread”。 可能的误区是用户可能混淆Join和其他线程同步机制,比如Task.Wait或者async/await,可能需要简单对比,但根据问题范围,可能不需要深入,除非必要。 还需要考虑示例代码的正确性,确保语法正确,比如Thread的创建和启动,Join的调用位置。 总结步骤: 1. 定义Join方法。 2. 解释作用:阻塞当前线程直到目标线程完成。 3. 使用场景:主线程等待子线程。 4. 代码示例:创建线程,启动,调用Join。 5. 注意事项:可能导致的死锁,合理使用。 6. 对比其他方法(可选)。 现在需要组织语言,确保结构清晰,逐步引导用户理解。同时检查是否有错误,比如Join是否会释放资源,或者是否需要处理异常等,但基础解释可能不需要太深入,除非用户问题涉及。 可能还需要提到,如果不使用Join,主线程可能会在子线程结束前就退出,导致程序提前终止。这时候用Join可以确保子线程完成任务。 最后,确保回答真实可靠,参考官方文档或权威资料,比如微软的C#文档中关于Thread.Join的部分。</think>在C#多线程编程中,`Join`方法是一个重要的线程同步机制。以下是逐步解释: --- ### 1. **基本定义** `Join`是`System.Threading.Thread`类的方法,其核心作用是:**阻塞当前线程,直到目标线程执行完成**。 示例: ```csharp Thread workerThread = new Thread(DoWork); workerThread.Start(); workerThread.Join(); // 当前线程在此等待workerThread结束 ``` --- ### 2. **作用详解** - **同步控制**:当调用`t.Join()`时,**调用方线程会暂停**,直到线程`t`终止。 - **资源协调**:确保某些操作必须在线程结束后才能继续(例如:依赖线程的计算结果)。 --- ### 3. **典型使用场景** #### 场景1:主线程等待子线程 ```csharp static void Main() { Thread childThread = new Thread(() => { Console.WriteLine("子线程开始工作"); Thread.Sleep(2000); Console.WriteLine("子线程结束"); }); childThread.Start(); childThread.Join(); // 主线程在此等待 Console.WriteLine("主线程继续执行"); } ``` 输出: ``` 子线程开始工作 (等待2秒) 子线程结束 主线程继续执行 ``` #### 场景2:多个线程顺序执行 ```csharp Thread t1 = new Thread(() => Console.WriteLine("线程1完成")); Thread t2 = new Thread(() => Console.WriteLine("线程2完成")); t1.Start(); t1.Join(); // 等待t1结束 t2.Start(); t2.Join(); // 等待t2结束 ``` --- ### 4. **关键特性** - **超时控制**:可通过参数设置最大等待时间(单位:毫秒): ```csharp bool isCompleted = workerThread.Join(1000); // 等待最多1秒 ``` - 返回`true`表示线程已结束 - 返回`false`表示超时 - **线程状态检查**:若线程未启动或已终止,`Join`会立即返回。 --- ### 5. **注意事项** - **死锁风险**:若两个线程互相调用`Join()`,会导致永久阻塞。 - **合理使用**:过度使用`Join`可能降低多线程的并发优势。 --- ### 6. **对比其他同步方式** | 方法 | 特点 | |---------------|----------------------------------| | `Join` | 直接线程级阻塞 | | `Task.Wait` | 用于Task任务的等待 | | `async/await` | 非阻塞异步模型,更现代 | --- ### 总结 `Join`方法本质是通过**阻塞调用线程**来实现同步,适用于需要严格顺序执行的场景。在实际开发中,应根据需求权衡其与异步编程模型(如`Task`)的选择。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值