当前位置:   article > 正文

如何使主线程等待子线程?_ios开发 主线程等待子线程执行结束 sema

ios开发 主线程等待子线程执行结束 sema

在这里插入图片描述

使用awaitTermination方法

当我们想使用多线程的方法去执行一些逻辑,并想要获取执行的结果的时候。
我们会创建一个线程池,然后使用submit方法提交任务。然后通过get方法去获取执行的结果。

<T> Future<T> submit(Callable<T> task);
  • 1

如果,想要所有的任务执行完毕后,主线程才继续往下执行。我们一般的做法是

public class ExTest {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        List<Future<XxxTask.Result>> futures = new ArrayList<>();
        futures.add(executorService.submit(new XxxTask(4000)));
        futures.add(executorService.submit(new XxxTask(3000)));
        futures.add(executorService.submit(new XxxTask(8000)));
        futures.add(executorService.submit(new XxxTask(1000)));

        long startAll = System.currentTimeMillis();
        executorService.shutdown();
        try {
            executorService.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        futures.forEach(x -> {
            try {
                long start = System.currentTimeMillis();
                XxxTask.Result result = x.get();
                long end = System.currentTimeMillis();
                System.out.println("当前线程" + Thread.currentThread() + "消耗了" + (end - start) / 1000);
                System.out.println();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });

        long endAll = System.currentTimeMillis();
        System.out.println("一共消耗了" + (endAll - startAll) / 1000 + "s");
    }
}

class XxxTask implements Callable<XxxTask.Result> {
    public XxxTask(Integer time) {
        this.time = time;
    }

    private Integer time;

    @Override
    public Result call() throws Exception {
        Thread.sleep(time);
        // do something
        return new Result();
    }

    public static class Result {
        public String message;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

将线程池 shutdown,就是平滑的停止(该方法会使线程池不再接受新的任务,已经接受的任务会继续执行完毕)。
awaitTermination方法需要和shutdown方法配合。其目的是使主线程堵塞,直到线程池任务执行完毕。
执行结果如下

当前线程Thread[main,5,main]消耗了0

当前线程Thread[main,5,main]消耗了0

当前线程Thread[main,5,main]消耗了0

当前线程Thread[main,5,main]消耗了0

一共消耗了8s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

之所以消耗都是0s,是因为在上面任务已经执行完了,调用get方法不会再消耗时间。

但是,如果上述代码是在一个接口中,对方会多次调用这个接口。这样写会产生的后果是,线程池频繁的创建以及销毁。会浪费很多资源。
因此 上述的代码尽量用来线程池创建的次数少的地方。比如发布项目时的数据初始化。只创建一个线程池。然后多个线程跑。而在接口中建议使用下面的方法。

使用Future接口的get方法

此get方法会获取任务所执行的结果。如果那个子线程没有执行完任务,主线程会一直堵塞直到获取到结果。
利用这个特点,我们要想主线程等待所有的子线程执行完毕,只要遍历Future,分别get即可。
代码如下所示

public class ExTest {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        List<Future<XxxTask.Result>> futures = new ArrayList<>();
        futures.add(executorService.submit(new XxxTask(4000)));
        futures.add(executorService.submit(new XxxTask(3000)));
        futures.add(executorService.submit(new XxxTask(8000)));
        futures.add(executorService.submit(new XxxTask(1000)));


        long startAll = System.currentTimeMillis();
        futures.forEach(x -> {
            try {
                long start = System.currentTimeMillis();
                XxxTask.Result result = x.get();
                long end = System.currentTimeMillis();
                System.out.println("当前线程" + Thread.currentThread() + "消耗了" + (end - start) / 1000);
                System.out.println();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });

        long endAll = System.currentTimeMillis();
        System.out.println("一共消耗了" + (endAll - startAll) / 1000 + "s");
    }
}

class XxxTask implements Callable<XxxTask.Result> {
    public XxxTask(Integer time) {
        this.time = time;
    }

    private Integer time;

    @Override
    public Result call() throws Exception {
        Thread.sleep(time);
        // do something
        return new Result();
    }

    public static class Result {
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

上述代码。简单的创建了一个线程池(暂不考虑OOM)。当在写业务代码的时候,将其作为一个成员变量,使用完之后,不要销毁即可。就可以实现线程池的重复使用。
并且可以同步的走完这个代码。让主线程等待子线程执行完毕之后再往下执行。
下面是执行的结果

当前线程Thread[main,5,main]消耗了3

当前线程Thread[main,5,main]消耗了0

当前线程Thread[main,5,main]消耗了3

当前线程Thread[main,5,main]消耗了0

一共消耗了8s

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

其中主线程在等待第一个任务时;第二,第三,第四的任务也已经开始执行了。同样是并行执行的,效率也不慢。

注意点

但是,千万要小心的是,千万不要这样写!!!

 ExecutorService executorService = Executors.newFixedThreadPool(5);
        long startAll = System.currentTimeMillis();
        Future<XxxTask.Result> submit = executorService.submit(new XxxTask(4000));
        submit.get();
        Future<XxxTask.Result> submit2 = executorService.submit(new XxxTask(3000));
        submit2.get();
        Future<XxxTask.Result> submit3 = executorService.submit(new XxxTask(8000));
        submit3.get();
        Future<XxxTask.Result> submit1 = executorService.submit(new XxxTask(1000));
        submit1.get();

        long endAll = System.currentTimeMillis();
        System.out.println("一共消耗了" + (endAll - startAll) / 1000 + "s");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这样会把多线程写成单线程的执行,切记切记。

使用闭锁CountDownLatch

有关闭锁的知识,请看这篇文章 -->

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号