Java多线程中join方法的理解

许多同学刚开始学Java 多线程时可能不会关主Join 这个动作,因为不知道它是用来做什么的,而当需要用到类似的场景时却有可能会说Java 没有提供这种功能。

当我们将一个大任务划分为多个小任务,多个小任务由多个线程去完成时,显然它们完成的先后顺序不可能完全一致。在程序中希望各个线程执行完成后,将它们的计算结果最终合并在一起,换句话说,要等待多个线程将子任务执行完成后,才能进行合并结果的操作。 这时就可以选择使用Join 了,Join 可以帮助我们轻松地搞定这个问题,否则就需要用个循环去不断判定每个线程的状态。

在实际生活中,就像把任务分解给多个人去完成其中的各个板块,但老板需要等待这些人全部都完成后才认为这个阶段的任务结束了,也许每个人的板块内部和别人还有相互的接口依赖,如果对方接口没有写好,自己的这部分也不算完全完成,就会发生类似于合并的动作(到底要将任务细化到什么粒度,完全看实际场景和自己对问题的理解)。下面用段简单的代码米说明Join 的使用。

thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

package com.sss.test;

import java.util.Random;

/**
 * @author Shusheng Shi
 */
public class ThreadJoinTest {
    static class Computer extends Thread {
        private int start;
        private int end;
        private int result;
        private int[] array;

        public Computer(int[] array, int start, int end) {
            this.array=array;
            this.start=start;
            this.end=end;
        }

        @Override
        public void run() {
            for (int i=start; i < end; i++) {
                result+=array[i];
            }

            if (result < 0) {
                result&=Integer.MAX_VALUE;
            }

        }

        public int getResult() {
            return result;

        }
    }

    private final static int COUNTER=10000000;

    public static void main(String[] args) throws InterruptedException {
        int[] array=new int[COUNTER];
        Random random=new Random();
        for (int i=0; i < COUNTER; i++) {
            array[i]=Math.abs( random.nextInt() );
        }
        long start=System.currentTimeMillis();
        Computer c1=new Computer( array, 0, COUNTER );
        Computer c2=new Computer( array, COUNTER / 2, COUNTER );
        c1.start();
        c2.start();
        c1.join();
        c2.join();
        System.out.println( System.currentTimeMillis() - start );
        System.out.println( (c1.getResult() + c2.getResult()) & Integer.MAX_VALUE );
    }
}

这个例子或许不太好,只是1000 万个随机数叠加,为了防此CPU计算过快,在计算中增加一些判定操作,最后再将计算完的两个值输出,也输出运算时间。如果在有多个CPU的机器上做测试,就会发现数据量大时,多个线程计算具有优势,但是这个优势非常小, 而且在数据量较小的情况下,单线程会更快些。为何单线程可能会更快呢? 最主要的原因是线程在分配时就有开销(每个线程的分配过程本身就高要执行很多条底层代码,这些代码的执行相当于很多条CPU 叠加运算的指令),Join 操作过程还有其他的各种开销。 如果尝试将每个线程叠加后做一些其他的操作,例如IO读写、字符串处理等操作,多线程的优势就出来了,因为这样总体计算下来后,线程的创建时间是可以被忽略

所以我们在考量系统的综合性能时不能就一一个点或某种测试就轻易得出一一个最终结论,定要考虑更多的变动因素。

那么使用多线程带来更多的是上下文切换的开销,多线程操作的共享对象还会有锁瓶 否则就是非线程安全的。 颈, 综合考量各种开销因素、时间、空间, 最后利用大量的场景测试来证明推理是有 指导性的,如果只是一味地为了用多线程而使用多线程,则往往很多事情可能会适得 其反 Join5 ?是语法层面的线程合并,其实它更像是当前线程处于BLOCKEN 状态时去等待 I :他线程结束的事件,而且是逐个去Join。换句话说,Join 的顺序并不一一定是线程真正结 束的顺序,要保证线程结束的顺J 字性,它还无法实现,即使在本例中它也不是唯一的实现 方式,本章后面会提到许多基于并发编程工具的方式来实现会更加理想,管理也会更加体 系化,能适应更多的业务场景需求。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FreeBuf

逆向工厂(二):静态分析技术

* 本文原创作者:追影人,本文属FreeBuf原创奖励计划,未经许可禁止转载 前言 [逆向工厂]第一章节中介绍了逆向技术的相关基础知识,其中提到逆向的两种形式:...

4188
来自专栏工科狗和生物喵

【计算机本科补全计划】指令:计算机的语言(MIPS) Part3

正文之前 今天学的很尴尬,因为有事情,而且新认识了两个计算机学院的保研大佬,不得不感叹我找的导师之强,第一个去上交的,是被金老师推荐去的,听说是跟了目前亚洲第一...

3208
来自专栏新智元

Go 2.0发布在即,程序员有太多话要说

Go语言的开发者正着手准备开发2.0版本,并从以下三个方面发布了初步的设计方案(非官方正式版),以供社区开展讨论:

5081
来自专栏FreeBuf

pwnable.tw刷题之dubblesort

前言 上一篇中我介绍了phttp://www.freebuf.com/articles/others-articles/134271.htmlwnable.tw...

3116
来自专栏PHP在线

URL短链接实现方法

最近项目开发中,需要实现URL长链接转短链接的需求,于是在网上找了一些资料,顺便整理了下,欢迎有想法的童鞋踊跃留言,我们共同探讨。

9998
来自专栏有趣的django

python开发面试问题

python语法以及其他基础部分 可变与不可变类型;  浅拷贝与深拷贝的实现方式、区别;deepcopy如果你来设计,如何实现;  __new__() 与 __...

4558
来自专栏用户2442861的专栏

最常用的两种C++序列化方案的使用心得(protobuf和boost serialization)

http://blog.csdn.net/lanxuezaipiao/article/details/24845625

6932
来自专栏熊二哥

GOF设计模式快速学习

这段时间,学习状态比较一般,空闲时基本都在打游戏,和研究如何打好游戏,终于通过戏命师烬制霸LOL,玩笑了。为了和"学习"之间的友谊小船不翻,决定对以往学习过的G...

1989
来自专栏Golang语言社区

Go语言是彻底的面向组合的并发语言

面向组合编程从AOP的Mixin,然后到Ruby的Traits,直至DCI设计,包括Scala的trait的组合设计,这些都有一个共同特点,组合特性是显式的,也...

3306
来自专栏程序员阿凯

JDK10 揭秘

1495

扫码关注云+社区